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 47namespace JSC { 48 49class DeadBlock : public HeapBlock<DeadBlock> { 50public: 51 DeadBlock(Region*); 52}; 53 54inline DeadBlock::DeadBlock(Region* region) 55 : HeapBlock<DeadBlock>(region) 56{ 57} 58 59class Region : public DoublyLinkedListNode<Region> { 60 WTF_MAKE_FAST_ALLOCATED; 61 62 friend class WTF::DoublyLinkedListNode<Region>; 63 friend class BlockAllocator; 64public: 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 82protected: 83 Region(size_t blockSize, size_t totalBlocks, bool isExcess); 84 void initializeBlockList(); 85 86 bool m_isExcess; 87 88private: 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 102class NormalRegion : public Region { 103 friend class Region; 104private: 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 118class ExcessRegion : public Region { 119 friend class Region; 120private: 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 136inline 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 143inline 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 151inline 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 160inline 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 167inline ExcessRegion::ExcessRegion(PageAllocationAligned& allocation, size_t blockSize, size_t totalBlocks) 168 : Region(blockSize, totalBlocks, true) 169 , m_allocation(allocation) 170{ 171 initializeBlockList(); 172} 173 174inline ExcessRegion::~ExcessRegion() 175{ 176 m_allocation.deallocate(); 177} 178 179inline 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 186inline 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 193inline 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 200inline 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 212inline 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 223inline 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 237inline 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 251inline Region::~Region() 252{ 253 ASSERT(isEmpty()); 254} 255 256inline 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 268inline 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 280inline DeadBlock* Region::allocate() 281{ 282 ASSERT(!isFull()); 283 m_blocksInUse++; 284 return m_deadBlocks.removeHead(); 285} 286 287inline 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 297inline 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 308inline 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 322