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 friend CLASS_IF_GCC DoublyLinkedListNode
<Region
>;
61 friend class BlockAllocator
;
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
);
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
; }
74 DeadBlock
* allocate();
75 void deallocate(void*);
77 static const size_t s_regionSize
= 64 * KB
;
78 static const size_t s_regionMask
= ~(s_regionSize
- 1);
81 Region(size_t blockSize
, size_t totalBlocks
, bool isExcess
);
82 void initializeBlockList();
96 DoublyLinkedList
<DeadBlock
> m_deadBlocks
;
100 class NormalRegion
: public Region
{
103 NormalRegion(PassRefPtr
<WTF::MetaAllocatorHandle
>, size_t blockSize
, size_t totalBlocks
);
105 static NormalRegion
* tryCreate(SuperRegion
*, size_t blockSize
);
106 static NormalRegion
* tryCreateCustomSize(SuperRegion
*, size_t blockSize
, size_t blockAlignment
);
108 void* base() { return m_allocation
->start(); }
109 size_t size() { return m_allocation
->sizeInBytes(); }
111 NormalRegion
* reset(size_t blockSize
);
113 RefPtr
<WTF::MetaAllocatorHandle
> m_allocation
;
116 class ExcessRegion
: public Region
{
119 ExcessRegion(PageAllocationAligned
&, size_t blockSize
, size_t totalBlocks
);
123 static ExcessRegion
* create(size_t blockSize
);
124 static ExcessRegion
* createCustomSize(size_t blockSize
, size_t blockAlignment
);
126 void* base() { return m_allocation
.base(); }
127 size_t size() { return m_allocation
.size(); }
129 ExcessRegion
* reset(size_t blockSize
);
131 PageAllocationAligned m_allocation
;
134 inline NormalRegion::NormalRegion(PassRefPtr
<WTF::MetaAllocatorHandle
> allocation
, size_t blockSize
, size_t totalBlocks
)
135 : Region(blockSize
, totalBlocks
, false)
136 , m_allocation(allocation
)
138 initializeBlockList();
141 inline NormalRegion
* NormalRegion::tryCreate(SuperRegion
* superRegion
, size_t blockSize
)
143 RefPtr
<WTF::MetaAllocatorHandle
> allocation
= superRegion
->allocate(s_regionSize
, HEAP_MEMORY_ID
);
146 return new NormalRegion(allocation
, blockSize
, s_regionSize
/ blockSize
);
149 inline NormalRegion
* NormalRegion::tryCreateCustomSize(SuperRegion
* superRegion
, size_t blockSize
, size_t blockAlignment
)
151 ASSERT_UNUSED(blockAlignment
, blockAlignment
<= s_regionSize
);
152 RefPtr
<WTF::MetaAllocatorHandle
> allocation
= superRegion
->allocate(blockSize
, HEAP_MEMORY_ID
);
155 return new NormalRegion(allocation
, blockSize
, 1);
158 inline NormalRegion
* NormalRegion::reset(size_t blockSize
)
161 RefPtr
<WTF::MetaAllocatorHandle
> allocation
= m_allocation
.release();
162 return new (NotNull
, this) NormalRegion(allocation
.release(), blockSize
, s_regionSize
/ blockSize
);
165 inline ExcessRegion::ExcessRegion(PageAllocationAligned
& allocation
, size_t blockSize
, size_t totalBlocks
)
166 : Region(blockSize
, totalBlocks
, true)
167 , m_allocation(allocation
)
169 initializeBlockList();
172 inline ExcessRegion::~ExcessRegion()
174 m_allocation
.deallocate();
177 inline ExcessRegion
* ExcessRegion::create(size_t blockSize
)
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
);
184 inline ExcessRegion
* ExcessRegion::createCustomSize(size_t blockSize
, size_t blockAlignment
)
186 PageAllocationAligned allocation
= PageAllocationAligned::allocate(blockSize
, blockAlignment
, OSAllocator::JSGCHeapPages
);
187 ASSERT(static_cast<bool>(allocation
));
188 return new ExcessRegion(allocation
, blockSize
, 1);
191 inline ExcessRegion
* ExcessRegion::reset(size_t blockSize
)
194 PageAllocationAligned allocation
= m_allocation
;
195 return new (NotNull
, this) ExcessRegion(allocation
, blockSize
, s_regionSize
/ blockSize
);
198 inline Region::Region(size_t blockSize
, size_t totalBlocks
, bool isExcess
)
199 : DoublyLinkedListNode
<Region
>()
200 , m_isExcess(isExcess
)
201 , m_totalBlocks(totalBlocks
)
203 , m_blockSize(blockSize
)
204 , m_isCustomSize(false)
210 inline void Region::initializeBlockList()
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
;
221 inline Region
* Region::create(SuperRegion
* superRegion
, size_t blockSize
)
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
))
230 UNUSED_PARAM(superRegion
);
232 return ExcessRegion::create(blockSize
);
235 inline Region
* Region::createCustomSize(SuperRegion
* superRegion
, size_t blockSize
, size_t blockAlignment
)
237 #if ENABLE(SUPER_REGION)
238 Region
* region
= NormalRegion::tryCreateCustomSize(superRegion
, blockSize
, blockAlignment
);
239 if (UNLIKELY(!region
))
240 region
= ExcessRegion::createCustomSize(blockSize
, blockAlignment
);
242 UNUSED_PARAM(superRegion
);
243 Region
* region
= ExcessRegion::createCustomSize(blockSize
, blockAlignment
);
245 region
->m_isCustomSize
= true;
249 inline Region::~Region()
254 inline void Region::destroy()
256 #if ENABLE(SUPER_REGION)
257 if (UNLIKELY(m_isExcess
))
258 delete static_cast<ExcessRegion
*>(this);
260 delete static_cast<NormalRegion
*>(this);
262 delete static_cast<ExcessRegion
*>(this);
266 inline Region
* Region::reset(size_t blockSize
)
268 #if ENABLE(SUPER_REGION)
270 if (UNLIKELY(m_isExcess
))
271 return static_cast<ExcessRegion
*>(this)->reset(blockSize
);
272 return static_cast<NormalRegion
*>(this)->reset(blockSize
);
274 return static_cast<ExcessRegion
*>(this)->reset(blockSize
);
278 inline DeadBlock
* Region::allocate()
282 return m_deadBlocks
.removeHead();
285 inline void Region::deallocate(void* 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
);
295 inline void* Region::base()
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();
302 return static_cast<ExcessRegion
*>(this)->ExcessRegion::base();
306 inline size_t Region::size()
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();
313 return static_cast<ExcessRegion
*>(this)->ExcessRegion::size();
319 #endif // JSC_Region_h