2 * Copyright (C) 2013 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #include "HeapBlock.h"
30 #include "SuperRegion.h"
31 #include <wtf/DoublyLinkedList.h>
32 #include <wtf/MetaAllocatorHandle.h>
33 #include <wtf/PageAllocationAligned.h>
35 #define HEAP_MEMORY_ID reinterpret_cast<void*>(static_cast<intptr_t>(-3))
37 #define ENABLE_SUPER_REGION 0
39 #ifndef ENABLE_SUPER_REGION
40 #if USE(JSVALUE64) && !CPU(ARM64)
41 #define ENABLE_SUPER_REGION 1
43 #define ENABLE_SUPER_REGION 0
49 class DeadBlock
: public HeapBlock
<DeadBlock
> {
54 inline DeadBlock::DeadBlock(Region
* region
)
55 : HeapBlock
<DeadBlock
>(region
)
59 class Region
: public DoublyLinkedListNode
<Region
> {
60 WTF_MAKE_FAST_ALLOCATED
;
62 friend class WTF::DoublyLinkedListNode
<Region
>;
63 friend class BlockAllocator
;
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
);
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
; }
76 DeadBlock
* allocate();
77 void deallocate(void*);
79 static const size_t s_regionSize
= 64 * KB
;
80 static const size_t s_regionMask
= ~(s_regionSize
- 1);
83 Region(size_t blockSize
, size_t totalBlocks
, bool isExcess
);
84 void initializeBlockList();
98 DoublyLinkedList
<DeadBlock
> m_deadBlocks
;
102 class NormalRegion
: public Region
{
105 NormalRegion(PassRefPtr
<WTF::MetaAllocatorHandle
>, size_t blockSize
, size_t totalBlocks
);
107 static NormalRegion
* tryCreate(SuperRegion
*, size_t blockSize
);
108 static NormalRegion
* tryCreateCustomSize(SuperRegion
*, size_t blockSize
, size_t blockAlignment
);
110 void* base() { return m_allocation
->start(); }
111 size_t size() { return m_allocation
->sizeInBytes(); }
113 NormalRegion
* reset(size_t blockSize
);
115 RefPtr
<WTF::MetaAllocatorHandle
> m_allocation
;
118 class ExcessRegion
: public Region
{
121 ExcessRegion(PageAllocationAligned
&, size_t blockSize
, size_t totalBlocks
);
125 static ExcessRegion
* create(size_t blockSize
);
126 static ExcessRegion
* createCustomSize(size_t blockSize
, size_t blockAlignment
);
128 void* base() { return m_allocation
.base(); }
129 size_t size() { return m_allocation
.size(); }
131 ExcessRegion
* reset(size_t blockSize
);
133 PageAllocationAligned m_allocation
;
136 inline NormalRegion::NormalRegion(PassRefPtr
<WTF::MetaAllocatorHandle
> allocation
, size_t blockSize
, size_t totalBlocks
)
137 : Region(blockSize
, totalBlocks
, false)
138 , m_allocation(allocation
)
140 initializeBlockList();
143 inline NormalRegion
* NormalRegion::tryCreate(SuperRegion
* superRegion
, size_t blockSize
)
145 RefPtr
<WTF::MetaAllocatorHandle
> allocation
= superRegion
->allocate(s_regionSize
, HEAP_MEMORY_ID
);
148 return new NormalRegion(allocation
, blockSize
, s_regionSize
/ blockSize
);
151 inline NormalRegion
* NormalRegion::tryCreateCustomSize(SuperRegion
* superRegion
, size_t blockSize
, size_t blockAlignment
)
153 ASSERT_UNUSED(blockAlignment
, blockAlignment
<= s_regionSize
);
154 RefPtr
<WTF::MetaAllocatorHandle
> allocation
= superRegion
->allocate(blockSize
, HEAP_MEMORY_ID
);
157 return new NormalRegion(allocation
, blockSize
, 1);
160 inline NormalRegion
* NormalRegion::reset(size_t blockSize
)
163 RefPtr
<WTF::MetaAllocatorHandle
> allocation
= m_allocation
.release();
164 return new (NotNull
, this) NormalRegion(allocation
.release(), blockSize
, s_regionSize
/ blockSize
);
167 inline ExcessRegion::ExcessRegion(PageAllocationAligned
& allocation
, size_t blockSize
, size_t totalBlocks
)
168 : Region(blockSize
, totalBlocks
, true)
169 , m_allocation(allocation
)
171 initializeBlockList();
174 inline ExcessRegion::~ExcessRegion()
176 m_allocation
.deallocate();
179 inline ExcessRegion
* ExcessRegion::create(size_t blockSize
)
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
);
186 inline ExcessRegion
* ExcessRegion::createCustomSize(size_t blockSize
, size_t blockAlignment
)
188 PageAllocationAligned allocation
= PageAllocationAligned::allocate(blockSize
, blockAlignment
, OSAllocator::JSGCHeapPages
);
189 ASSERT(static_cast<bool>(allocation
));
190 return new ExcessRegion(allocation
, blockSize
, 1);
193 inline ExcessRegion
* ExcessRegion::reset(size_t blockSize
)
196 PageAllocationAligned allocation
= m_allocation
;
197 return new (NotNull
, this) ExcessRegion(allocation
, blockSize
, s_regionSize
/ blockSize
);
200 inline Region::Region(size_t blockSize
, size_t totalBlocks
, bool isExcess
)
201 : DoublyLinkedListNode
<Region
>()
202 , m_isExcess(isExcess
)
203 , m_totalBlocks(totalBlocks
)
205 , m_blockSize(blockSize
)
206 , m_isCustomSize(false)
212 inline void Region::initializeBlockList()
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
;
223 inline Region
* Region::create(SuperRegion
* superRegion
, size_t blockSize
)
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
))
232 UNUSED_PARAM(superRegion
);
234 return ExcessRegion::create(blockSize
);
237 inline Region
* Region::createCustomSize(SuperRegion
* superRegion
, size_t blockSize
, size_t blockAlignment
)
239 #if ENABLE(SUPER_REGION)
240 Region
* region
= NormalRegion::tryCreateCustomSize(superRegion
, blockSize
, blockAlignment
);
241 if (UNLIKELY(!region
))
242 region
= ExcessRegion::createCustomSize(blockSize
, blockAlignment
);
244 UNUSED_PARAM(superRegion
);
245 Region
* region
= ExcessRegion::createCustomSize(blockSize
, blockAlignment
);
247 region
->m_isCustomSize
= true;
251 inline Region::~Region()
256 inline void Region::destroy()
258 #if ENABLE(SUPER_REGION)
259 if (UNLIKELY(m_isExcess
))
260 delete static_cast<ExcessRegion
*>(this);
262 delete static_cast<NormalRegion
*>(this);
264 delete static_cast<ExcessRegion
*>(this);
268 inline Region
* Region::reset(size_t blockSize
)
270 #if ENABLE(SUPER_REGION)
272 if (UNLIKELY(m_isExcess
))
273 return static_cast<ExcessRegion
*>(this)->reset(blockSize
);
274 return static_cast<NormalRegion
*>(this)->reset(blockSize
);
276 return static_cast<ExcessRegion
*>(this)->reset(blockSize
);
280 inline DeadBlock
* Region::allocate()
284 return m_deadBlocks
.removeHead();
287 inline void Region::deallocate(void* 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
);
297 inline void* Region::base()
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();
304 return static_cast<ExcessRegion
*>(this)->ExcessRegion::base();
308 inline size_t Region::size()
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();
315 return static_cast<ExcessRegion
*>(this)->ExcessRegion::size();
321 #endif // JSC_Region_h