]> git.saurik.com Git - apple/javascriptcore.git/blob - heap/Region.h
JavaScriptCore-7600.1.4.17.5.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 WTF_MAKE_FAST_ALLOCATED;
61
62 friend class WTF::DoublyLinkedListNode<Region>;
63 friend class BlockAllocator;
64 public:
65 ~Region();
66 static Region* create(SuperRegion*, size_t blockSize);
67 static Region* createCustomSize(SuperRegion*, size_t blockSize, size_t blockAlignment);
68 Region* reset(size_t blockSize);
69 void destroy();
70
71 size_t blockSize() const { return m_blockSize; }
72 bool isFull() const { return m_blocksInUse == m_totalBlocks; }
73 bool isEmpty() const { return !m_blocksInUse; }
74 bool isCustomSize() const { return m_isCustomSize; }
75
76 DeadBlock* allocate();
77 void deallocate(void*);
78
79 static const size_t s_regionSize = 64 * KB;
80 static const size_t s_regionMask = ~(s_regionSize - 1);
81
82 protected:
83 Region(size_t blockSize, size_t totalBlocks, bool isExcess);
84 void initializeBlockList();
85
86 bool m_isExcess;
87
88 private:
89 void* base();
90 size_t size();
91
92 size_t m_totalBlocks;
93 size_t m_blocksInUse;
94 size_t m_blockSize;
95 bool m_isCustomSize;
96 Region* m_prev;
97 Region* m_next;
98 DoublyLinkedList<DeadBlock> m_deadBlocks;
99 };
100
101
102 class NormalRegion : public Region {
103 friend class Region;
104 private:
105 NormalRegion(PassRefPtr<WTF::MetaAllocatorHandle>, size_t blockSize, size_t totalBlocks);
106
107 static NormalRegion* tryCreate(SuperRegion*, size_t blockSize);
108 static NormalRegion* tryCreateCustomSize(SuperRegion*, size_t blockSize, size_t blockAlignment);
109
110 void* base() { return m_allocation->start(); }
111 size_t size() { return m_allocation->sizeInBytes(); }
112
113 NormalRegion* reset(size_t blockSize);
114
115 RefPtr<WTF::MetaAllocatorHandle> m_allocation;
116 };
117
118 class ExcessRegion : public Region {
119 friend class Region;
120 private:
121 ExcessRegion(PageAllocationAligned&, size_t blockSize, size_t totalBlocks);
122
123 ~ExcessRegion();
124
125 static ExcessRegion* create(size_t blockSize);
126 static ExcessRegion* createCustomSize(size_t blockSize, size_t blockAlignment);
127
128 void* base() { return m_allocation.base(); }
129 size_t size() { return m_allocation.size(); }
130
131 ExcessRegion* reset(size_t blockSize);
132
133 PageAllocationAligned m_allocation;
134 };
135
136 inline NormalRegion::NormalRegion(PassRefPtr<WTF::MetaAllocatorHandle> allocation, size_t blockSize, size_t totalBlocks)
137 : Region(blockSize, totalBlocks, false)
138 , m_allocation(allocation)
139 {
140 initializeBlockList();
141 }
142
143 inline NormalRegion* NormalRegion::tryCreate(SuperRegion* superRegion, size_t blockSize)
144 {
145 RefPtr<WTF::MetaAllocatorHandle> allocation = superRegion->allocate(s_regionSize, HEAP_MEMORY_ID);
146 if (!allocation)
147 return 0;
148 return new NormalRegion(allocation, blockSize, s_regionSize / blockSize);
149 }
150
151 inline NormalRegion* NormalRegion::tryCreateCustomSize(SuperRegion* superRegion, size_t blockSize, size_t blockAlignment)
152 {
153 ASSERT_UNUSED(blockAlignment, blockAlignment <= s_regionSize);
154 RefPtr<WTF::MetaAllocatorHandle> allocation = superRegion->allocate(blockSize, HEAP_MEMORY_ID);
155 if (!allocation)
156 return 0;
157 return new NormalRegion(allocation, blockSize, 1);
158 }
159
160 inline NormalRegion* NormalRegion::reset(size_t blockSize)
161 {
162 ASSERT(!m_isExcess);
163 RefPtr<WTF::MetaAllocatorHandle> allocation = m_allocation.release();
164 return new (NotNull, this) NormalRegion(allocation.release(), blockSize, s_regionSize / blockSize);
165 }
166
167 inline ExcessRegion::ExcessRegion(PageAllocationAligned& allocation, size_t blockSize, size_t totalBlocks)
168 : Region(blockSize, totalBlocks, true)
169 , m_allocation(allocation)
170 {
171 initializeBlockList();
172 }
173
174 inline ExcessRegion::~ExcessRegion()
175 {
176 m_allocation.deallocate();
177 }
178
179 inline ExcessRegion* ExcessRegion::create(size_t blockSize)
180 {
181 PageAllocationAligned allocation = PageAllocationAligned::allocate(s_regionSize, s_regionSize, OSAllocator::JSGCHeapPages);
182 ASSERT(static_cast<bool>(allocation));
183 return new ExcessRegion(allocation, blockSize, s_regionSize / blockSize);
184 }
185
186 inline ExcessRegion* ExcessRegion::createCustomSize(size_t blockSize, size_t blockAlignment)
187 {
188 PageAllocationAligned allocation = PageAllocationAligned::allocate(blockSize, blockAlignment, OSAllocator::JSGCHeapPages);
189 ASSERT(static_cast<bool>(allocation));
190 return new ExcessRegion(allocation, blockSize, 1);
191 }
192
193 inline ExcessRegion* ExcessRegion::reset(size_t blockSize)
194 {
195 ASSERT(m_isExcess);
196 PageAllocationAligned allocation = m_allocation;
197 return new (NotNull, this) ExcessRegion(allocation, blockSize, s_regionSize / blockSize);
198 }
199
200 inline Region::Region(size_t blockSize, size_t totalBlocks, bool isExcess)
201 : DoublyLinkedListNode<Region>()
202 , m_isExcess(isExcess)
203 , m_totalBlocks(totalBlocks)
204 , m_blocksInUse(0)
205 , m_blockSize(blockSize)
206 , m_isCustomSize(false)
207 , m_prev(0)
208 , m_next(0)
209 {
210 }
211
212 inline void Region::initializeBlockList()
213 {
214 char* start = static_cast<char*>(base());
215 char* current = start;
216 for (size_t i = 0; i < m_totalBlocks; i++) {
217 ASSERT(current < start + size());
218 m_deadBlocks.append(new (NotNull, current) DeadBlock(this));
219 current += m_blockSize;
220 }
221 }
222
223 inline Region* Region::create(SuperRegion* superRegion, size_t blockSize)
224 {
225 #if ENABLE(SUPER_REGION)
226 ASSERT(blockSize <= s_regionSize);
227 ASSERT(!(s_regionSize % blockSize));
228 Region* region = NormalRegion::tryCreate(superRegion, blockSize);
229 if (LIKELY(!!region))
230 return region;
231 #else
232 UNUSED_PARAM(superRegion);
233 #endif
234 return ExcessRegion::create(blockSize);
235 }
236
237 inline Region* Region::createCustomSize(SuperRegion* superRegion, size_t blockSize, size_t blockAlignment)
238 {
239 #if ENABLE(SUPER_REGION)
240 Region* region = NormalRegion::tryCreateCustomSize(superRegion, blockSize, blockAlignment);
241 if (UNLIKELY(!region))
242 region = ExcessRegion::createCustomSize(blockSize, blockAlignment);
243 #else
244 UNUSED_PARAM(superRegion);
245 Region* region = ExcessRegion::createCustomSize(blockSize, blockAlignment);
246 #endif
247 region->m_isCustomSize = true;
248 return region;
249 }
250
251 inline Region::~Region()
252 {
253 ASSERT(isEmpty());
254 }
255
256 inline void Region::destroy()
257 {
258 #if ENABLE(SUPER_REGION)
259 if (UNLIKELY(m_isExcess))
260 delete static_cast<ExcessRegion*>(this);
261 else
262 delete static_cast<NormalRegion*>(this);
263 #else
264 delete static_cast<ExcessRegion*>(this);
265 #endif
266 }
267
268 inline Region* Region::reset(size_t blockSize)
269 {
270 #if ENABLE(SUPER_REGION)
271 ASSERT(isEmpty());
272 if (UNLIKELY(m_isExcess))
273 return static_cast<ExcessRegion*>(this)->reset(blockSize);
274 return static_cast<NormalRegion*>(this)->reset(blockSize);
275 #else
276 return static_cast<ExcessRegion*>(this)->reset(blockSize);
277 #endif
278 }
279
280 inline DeadBlock* Region::allocate()
281 {
282 ASSERT(!isFull());
283 m_blocksInUse++;
284 return m_deadBlocks.removeHead();
285 }
286
287 inline void Region::deallocate(void* base)
288 {
289 ASSERT(base);
290 ASSERT(m_blocksInUse);
291 ASSERT(base >= this->base() && base < static_cast<char*>(this->base()) + size());
292 DeadBlock* block = new (NotNull, base) DeadBlock(this);
293 m_deadBlocks.push(block);
294 m_blocksInUse--;
295 }
296
297 inline void* Region::base()
298 {
299 #if ENABLE(SUPER_REGION)
300 if (UNLIKELY(m_isExcess))
301 return static_cast<ExcessRegion*>(this)->ExcessRegion::base();
302 return static_cast<NormalRegion*>(this)->NormalRegion::base();
303 #else
304 return static_cast<ExcessRegion*>(this)->ExcessRegion::base();
305 #endif
306 }
307
308 inline size_t Region::size()
309 {
310 #if ENABLE(SUPER_REGION)
311 if (UNLIKELY(m_isExcess))
312 return static_cast<ExcessRegion*>(this)->ExcessRegion::size();
313 return static_cast<NormalRegion*>(this)->NormalRegion::size();
314 #else
315 return static_cast<ExcessRegion*>(this)->ExcessRegion::size();
316 #endif
317 }
318
319 } // namespace JSC
320
321 #endif // JSC_Region_h