]> git.saurik.com Git - apple/javascriptcore.git/blob - heap/Region.h
JavaScriptCore-1218.33.tar.gz
[apple/javascriptcore.git] / heap / Region.h
1 /*
2 * Copyright (C) 2013 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. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #ifndef JSC_Region_h
27 #define JSC_Region_h
28
29 #include "HeapBlock.h"
30 #include "SuperRegion.h"
31 #include <wtf/DoublyLinkedList.h>
32 #include <wtf/MetaAllocatorHandle.h>
33 #include <wtf/PageAllocationAligned.h>
34
35 #define HEAP_MEMORY_ID reinterpret_cast<void*>(static_cast<intptr_t>(-3))
36
37 #define ENABLE_SUPER_REGION 0
38
39 #ifndef ENABLE_SUPER_REGION
40 #if USE(JSVALUE64) && !CPU(ARM64)
41 #define ENABLE_SUPER_REGION 1
42 #else
43 #define ENABLE_SUPER_REGION 0
44 #endif
45 #endif
46
47 namespace JSC {
48
49 class DeadBlock : public HeapBlock<DeadBlock> {
50 public:
51 DeadBlock(Region*);
52 };
53
54 inline DeadBlock::DeadBlock(Region* region)
55 : HeapBlock<DeadBlock>(region)
56 {
57 }
58
59 class Region : public DoublyLinkedListNode<Region> {
60 friend CLASS_IF_GCC DoublyLinkedListNode<Region>;
61 friend class BlockAllocator;
62 public:
63 ~Region();
64 static Region* create(SuperRegion*, size_t blockSize);
65 static Region* createCustomSize(SuperRegion*, size_t blockSize, size_t blockAlignment);
66 Region* reset(size_t blockSize);
67 void destroy();
68
69 size_t blockSize() const { return m_blockSize; }
70 bool isFull() const { return m_blocksInUse == m_totalBlocks; }
71 bool isEmpty() const { return !m_blocksInUse; }
72 bool isCustomSize() const { return m_isCustomSize; }
73
74 DeadBlock* allocate();
75 void deallocate(void*);
76
77 static const size_t s_regionSize = 64 * KB;
78 static const size_t s_regionMask = ~(s_regionSize - 1);
79
80 protected:
81 Region(size_t blockSize, size_t totalBlocks, bool isExcess);
82 void initializeBlockList();
83
84 bool m_isExcess;
85
86 private:
87 void* base();
88 size_t size();
89
90 size_t m_totalBlocks;
91 size_t m_blocksInUse;
92 size_t m_blockSize;
93 bool m_isCustomSize;
94 Region* m_prev;
95 Region* m_next;
96 DoublyLinkedList<DeadBlock> m_deadBlocks;
97 };
98
99
100 class NormalRegion : public Region {
101 friend class Region;
102 private:
103 NormalRegion(PassRefPtr<WTF::MetaAllocatorHandle>, size_t blockSize, size_t totalBlocks);
104
105 static NormalRegion* tryCreate(SuperRegion*, size_t blockSize);
106 static NormalRegion* tryCreateCustomSize(SuperRegion*, size_t blockSize, size_t blockAlignment);
107
108 void* base() { return m_allocation->start(); }
109 size_t size() { return m_allocation->sizeInBytes(); }
110
111 NormalRegion* reset(size_t blockSize);
112
113 RefPtr<WTF::MetaAllocatorHandle> m_allocation;
114 };
115
116 class ExcessRegion : public Region {
117 friend class Region;
118 private:
119 ExcessRegion(PageAllocationAligned&, size_t blockSize, size_t totalBlocks);
120
121 ~ExcessRegion();
122
123 static ExcessRegion* create(size_t blockSize);
124 static ExcessRegion* createCustomSize(size_t blockSize, size_t blockAlignment);
125
126 void* base() { return m_allocation.base(); }
127 size_t size() { return m_allocation.size(); }
128
129 ExcessRegion* reset(size_t blockSize);
130
131 PageAllocationAligned m_allocation;
132 };
133
134 inline NormalRegion::NormalRegion(PassRefPtr<WTF::MetaAllocatorHandle> allocation, size_t blockSize, size_t totalBlocks)
135 : Region(blockSize, totalBlocks, false)
136 , m_allocation(allocation)
137 {
138 initializeBlockList();
139 }
140
141 inline NormalRegion* NormalRegion::tryCreate(SuperRegion* superRegion, size_t blockSize)
142 {
143 RefPtr<WTF::MetaAllocatorHandle> allocation = superRegion->allocate(s_regionSize, HEAP_MEMORY_ID);
144 if (!allocation)
145 return 0;
146 return new NormalRegion(allocation, blockSize, s_regionSize / blockSize);
147 }
148
149 inline NormalRegion* NormalRegion::tryCreateCustomSize(SuperRegion* superRegion, size_t blockSize, size_t blockAlignment)
150 {
151 ASSERT_UNUSED(blockAlignment, blockAlignment <= s_regionSize);
152 RefPtr<WTF::MetaAllocatorHandle> allocation = superRegion->allocate(blockSize, HEAP_MEMORY_ID);
153 if (!allocation)
154 return 0;
155 return new NormalRegion(allocation, blockSize, 1);
156 }
157
158 inline NormalRegion* NormalRegion::reset(size_t blockSize)
159 {
160 ASSERT(!m_isExcess);
161 RefPtr<WTF::MetaAllocatorHandle> allocation = m_allocation.release();
162 return new (NotNull, this) NormalRegion(allocation.release(), blockSize, s_regionSize / blockSize);
163 }
164
165 inline ExcessRegion::ExcessRegion(PageAllocationAligned& allocation, size_t blockSize, size_t totalBlocks)
166 : Region(blockSize, totalBlocks, true)
167 , m_allocation(allocation)
168 {
169 initializeBlockList();
170 }
171
172 inline ExcessRegion::~ExcessRegion()
173 {
174 m_allocation.deallocate();
175 }
176
177 inline ExcessRegion* ExcessRegion::create(size_t blockSize)
178 {
179 PageAllocationAligned allocation = PageAllocationAligned::allocate(s_regionSize, s_regionSize, OSAllocator::JSGCHeapPages);
180 ASSERT(static_cast<bool>(allocation));
181 return new ExcessRegion(allocation, blockSize, s_regionSize / blockSize);
182 }
183
184 inline ExcessRegion* ExcessRegion::createCustomSize(size_t blockSize, size_t blockAlignment)
185 {
186 PageAllocationAligned allocation = PageAllocationAligned::allocate(blockSize, blockAlignment, OSAllocator::JSGCHeapPages);
187 ASSERT(static_cast<bool>(allocation));
188 return new ExcessRegion(allocation, blockSize, 1);
189 }
190
191 inline ExcessRegion* ExcessRegion::reset(size_t blockSize)
192 {
193 ASSERT(m_isExcess);
194 PageAllocationAligned allocation = m_allocation;
195 return new (NotNull, this) ExcessRegion(allocation, blockSize, s_regionSize / blockSize);
196 }
197
198 inline Region::Region(size_t blockSize, size_t totalBlocks, bool isExcess)
199 : DoublyLinkedListNode<Region>()
200 , m_isExcess(isExcess)
201 , m_totalBlocks(totalBlocks)
202 , m_blocksInUse(0)
203 , m_blockSize(blockSize)
204 , m_isCustomSize(false)
205 , m_prev(0)
206 , m_next(0)
207 {
208 }
209
210 inline void Region::initializeBlockList()
211 {
212 char* start = static_cast<char*>(base());
213 char* current = start;
214 for (size_t i = 0; i < m_totalBlocks; i++) {
215 ASSERT(current < start + size());
216 m_deadBlocks.append(new (NotNull, current) DeadBlock(this));
217 current += m_blockSize;
218 }
219 }
220
221 inline Region* Region::create(SuperRegion* superRegion, size_t blockSize)
222 {
223 #if ENABLE(SUPER_REGION)
224 ASSERT(blockSize <= s_regionSize);
225 ASSERT(!(s_regionSize % blockSize));
226 Region* region = NormalRegion::tryCreate(superRegion, blockSize);
227 if (LIKELY(!!region))
228 return region;
229 #else
230 UNUSED_PARAM(superRegion);
231 #endif
232 return ExcessRegion::create(blockSize);
233 }
234
235 inline Region* Region::createCustomSize(SuperRegion* superRegion, size_t blockSize, size_t blockAlignment)
236 {
237 #if ENABLE(SUPER_REGION)
238 Region* region = NormalRegion::tryCreateCustomSize(superRegion, blockSize, blockAlignment);
239 if (UNLIKELY(!region))
240 region = ExcessRegion::createCustomSize(blockSize, blockAlignment);
241 #else
242 UNUSED_PARAM(superRegion);
243 Region* region = ExcessRegion::createCustomSize(blockSize, blockAlignment);
244 #endif
245 region->m_isCustomSize = true;
246 return region;
247 }
248
249 inline Region::~Region()
250 {
251 ASSERT(isEmpty());
252 }
253
254 inline void Region::destroy()
255 {
256 #if ENABLE(SUPER_REGION)
257 if (UNLIKELY(m_isExcess))
258 delete static_cast<ExcessRegion*>(this);
259 else
260 delete static_cast<NormalRegion*>(this);
261 #else
262 delete static_cast<ExcessRegion*>(this);
263 #endif
264 }
265
266 inline Region* Region::reset(size_t blockSize)
267 {
268 #if ENABLE(SUPER_REGION)
269 ASSERT(isEmpty());
270 if (UNLIKELY(m_isExcess))
271 return static_cast<ExcessRegion*>(this)->reset(blockSize);
272 return static_cast<NormalRegion*>(this)->reset(blockSize);
273 #else
274 return static_cast<ExcessRegion*>(this)->reset(blockSize);
275 #endif
276 }
277
278 inline DeadBlock* Region::allocate()
279 {
280 ASSERT(!isFull());
281 m_blocksInUse++;
282 return m_deadBlocks.removeHead();
283 }
284
285 inline void Region::deallocate(void* base)
286 {
287 ASSERT(base);
288 ASSERT(m_blocksInUse);
289 ASSERT(base >= this->base() && base < static_cast<char*>(this->base()) + size());
290 DeadBlock* block = new (NotNull, base) DeadBlock(this);
291 m_deadBlocks.push(block);
292 m_blocksInUse--;
293 }
294
295 inline void* Region::base()
296 {
297 #if ENABLE(SUPER_REGION)
298 if (UNLIKELY(m_isExcess))
299 return static_cast<ExcessRegion*>(this)->ExcessRegion::base();
300 return static_cast<NormalRegion*>(this)->NormalRegion::base();
301 #else
302 return static_cast<ExcessRegion*>(this)->ExcessRegion::base();
303 #endif
304 }
305
306 inline size_t Region::size()
307 {
308 #if ENABLE(SUPER_REGION)
309 if (UNLIKELY(m_isExcess))
310 return static_cast<ExcessRegion*>(this)->ExcessRegion::size();
311 return static_cast<NormalRegion*>(this)->NormalRegion::size();
312 #else
313 return static_cast<ExcessRegion*>(this)->ExcessRegion::size();
314 #endif
315 }
316
317 } // namespace JSC
318
319 #endif // JSC_Region_h