[BMalloc] Scavenger should react to recent memory activity
[WebKit-https.git] / Source / bmalloc / bmalloc / Chunk.h
1 /*
2  * Copyright (C) 2014 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #ifndef Chunk_h
27 #define Chunk_h
28
29 #include "Object.h"
30 #include "Sizes.h"
31 #include "SmallLine.h"
32 #include "SmallPage.h"
33 #include "VMAllocate.h"
34 #include <array>
35
36 namespace bmalloc {
37
38 class Chunk : public ListNode<Chunk> {
39 public:
40     static Chunk* get(void*);
41
42     Chunk(size_t pageSize);
43     
44     void ref() { ++m_refCount; }
45     void deref() { BASSERT(m_refCount); --m_refCount; }
46     unsigned refCount() { return m_refCount; }
47
48     bool usedSinceLastScavenge() { return m_usedSinceLastScavenge; }
49     void clearUsedSinceLastScavenge() { m_usedSinceLastScavenge = false; }
50     void setUsedSinceLastScavenge() { m_usedSinceLastScavenge = true; }
51
52     size_t offset(void*);
53
54     char* address(size_t offset);
55     SmallPage* page(size_t offset);
56     SmallLine* line(size_t offset);
57
58     char* bytes() { return reinterpret_cast<char*>(this); }
59     SmallLine* lines() { return &m_lines[0]; }
60     SmallPage* pages() { return &m_pages[0]; }
61     
62     List<SmallPage>& freePages() { return m_freePages; }
63
64 private:
65     size_t m_refCount { };
66     bool m_usedSinceLastScavenge: 1;
67     List<SmallPage> m_freePages { };
68
69     std::array<SmallLine, chunkSize / smallLineSize> m_lines { };
70     std::array<SmallPage, chunkSize / smallPageSize> m_pages { };
71 };
72
73 struct ChunkHash {
74     static unsigned hash(Chunk* key)
75     {
76         return static_cast<unsigned>(
77             reinterpret_cast<uintptr_t>(key) / chunkSize);
78     }
79 };
80
81 template<typename Function> void forEachPage(Chunk* chunk, size_t pageSize, Function function)
82 {
83     // We align to at least the page size so we can service aligned allocations
84     // at equal and smaller powers of two, and also so we can vmDeallocatePhysicalPages().
85     size_t metadataSize = roundUpToMultipleOfNonPowerOfTwo(pageSize, sizeof(Chunk));
86
87     Object begin(chunk, metadataSize);
88     Object end(chunk, chunkSize);
89
90     for (auto it = begin; it + pageSize <= end; it = it + pageSize)
91         function(it.page());
92 }
93
94 inline Chunk::Chunk(size_t pageSize)
95 {
96     size_t smallPageCount = pageSize / smallPageSize;
97     forEachPage(this, pageSize, [&](SmallPage* page) {
98         for (size_t i = 0; i < smallPageCount; ++i)
99             page[i].setSlide(i);
100     });
101 }
102
103 inline Chunk* Chunk::get(void* address)
104 {
105     return static_cast<Chunk*>(mask(address, chunkMask));
106 }
107
108 inline size_t Chunk::offset(void* address)
109 {
110     BASSERT(address >= this);
111     BASSERT(address < bytes() + chunkSize);
112     return static_cast<char*>(address) - bytes();
113 }
114
115 inline char* Chunk::address(size_t offset)
116 {
117     return bytes() + offset;
118 }
119
120 inline SmallPage* Chunk::page(size_t offset)
121 {
122     size_t pageNumber = offset / smallPageSize;
123     SmallPage* page = &m_pages[pageNumber];
124     return page - page->slide();
125 }
126
127 inline SmallLine* Chunk::line(size_t offset)
128 {
129     size_t lineNumber = offset / smallLineSize;
130     return &m_lines[lineNumber];
131 }
132
133 inline char* SmallLine::begin()
134 {
135     Chunk* chunk = Chunk::get(this);
136     size_t lineNumber = this - chunk->lines();
137     size_t offset = lineNumber * smallLineSize;
138     return &reinterpret_cast<char*>(chunk)[offset];
139 }
140
141 inline char* SmallLine::end()
142 {
143     return begin() + smallLineSize;
144 }
145
146 inline SmallLine* SmallPage::begin()
147 {
148     BASSERT(!m_slide);
149     Chunk* chunk = Chunk::get(this);
150     size_t pageNumber = this - chunk->pages();
151     size_t lineNumber = pageNumber * smallPageLineCount;
152     return &chunk->lines()[lineNumber];
153 }
154
155 inline Object::Object(void* object)
156     : m_chunk(Chunk::get(object))
157     , m_offset(m_chunk->offset(object))
158 {
159 }
160
161 inline Object::Object(Chunk* chunk, void* object)
162     : m_chunk(chunk)
163     , m_offset(m_chunk->offset(object))
164 {
165     BASSERT(chunk == Chunk::get(object));
166 }
167
168 inline char* Object::address()
169 {
170     return m_chunk->address(m_offset);
171 }
172
173 inline SmallLine* Object::line()
174 {
175     return m_chunk->line(m_offset);
176 }
177
178 inline SmallPage* Object::page()
179 {
180     return m_chunk->page(m_offset);
181 }
182
183 }; // namespace bmalloc
184
185 #endif // Chunk