2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "MachineStackMarker.h"
26 #include "MarkedBlock.h"
27 #include "PageAllocationAligned.h"
28 #include <wtf/Bitmap.h>
29 #include <wtf/DoublyLinkedList.h>
30 #include <wtf/FixedArray.h>
31 #include <wtf/HashSet.h>
32 #include <wtf/Noncopyable.h>
33 #include <wtf/Vector.h>
35 #define ASSERT_CLASS_FITS_IN_CELL(class) COMPILE_ASSERT(sizeof(class) < NewSpace::maxCellSize, class_fits_in_cell)
41 class LiveObjectIterator;
46 WTF_MAKE_NONCOPYABLE(NewSpace);
48 static const size_t maxCellSize = 1024;
49 static const size_t PropertyStorageNurserySize = 4 * MB;
53 void resetAllocator();
54 void canonicalizeBlock();
56 MarkedBlock::FreeCell* firstFreeCell;
57 MarkedBlock* currentBlock;
58 MarkedBlock* nextBlock;
59 DoublyLinkedList<MarkedBlock> blockList;
65 SizeClass& sizeClassFor(size_t);
66 void* allocate(SizeClass&);
67 inline void* allocatePropertyStorage(size_t);
68 inline bool inPropertyStorageNursery(void* ptr);
69 inline void resetPropertyStorageNursery();
71 void resetAllocator();
73 void addBlock(SizeClass&, MarkedBlock*);
74 void removeBlock(MarkedBlock*);
76 void canonicalizeBlocks();
79 size_t highWaterMark();
80 void setHighWaterMark(size_t);
82 template<typename Functor> typename Functor::ReturnType forEachBlock(Functor&); // Safe to remove the current item while iterating.
83 template<typename Functor> typename Functor::ReturnType forEachBlock();
87 static const size_t preciseStep = MarkedBlock::atomSize;
88 static const size_t preciseCutoff = 128;
89 static const size_t maximumPreciseAllocationSize = preciseCutoff - preciseStep;
90 static const size_t preciseCount = preciseCutoff / preciseStep - 1;
92 // [ 128, 256... 1024 )
93 static const size_t impreciseStep = preciseCutoff;
94 static const size_t impreciseCutoff = maxCellSize;
95 static const size_t impreciseCount = impreciseCutoff / impreciseStep - 1;
97 SizeClass m_preciseSizeClasses[preciseCount];
98 SizeClass m_impreciseSizeClasses[impreciseCount];
99 char* m_propertyStorageNursery;
100 char* m_propertyStorageAllocationPoint;
102 size_t m_highWaterMark;
106 inline size_t NewSpace::waterMark()
111 inline size_t NewSpace::highWaterMark()
113 return m_highWaterMark;
116 inline void NewSpace::setHighWaterMark(size_t highWaterMark)
118 m_highWaterMark = highWaterMark;
121 inline NewSpace::SizeClass& NewSpace::sizeClassFor(size_t bytes)
123 ASSERT(bytes && bytes < maxCellSize);
124 if (bytes <= maximumPreciseAllocationSize)
125 return m_preciseSizeClasses[(bytes - 1) / preciseStep];
126 return m_impreciseSizeClasses[(bytes - 1) / impreciseStep];
129 inline void* NewSpace::allocate(SizeClass& sizeClass)
131 MarkedBlock::FreeCell* firstFreeCell = sizeClass.firstFreeCell;
132 if (!firstFreeCell) {
133 // There are two possibilities for why we got here:
134 // 1) We've exhausted the allocation cache for currentBlock, in which case
135 // currentBlock == nextBlock, and we know that there is no reason to
136 // repeat a lazy sweep of nextBlock because we won't find anything.
137 // 2) Allocation caches have been cleared, in which case nextBlock may
138 // have (and most likely does have) free cells, so we almost certainly
139 // should do a lazySweep for nextBlock. This also implies that
140 // currentBlock == 0.
142 if (sizeClass.currentBlock) {
143 ASSERT(sizeClass.currentBlock == sizeClass.nextBlock);
144 m_waterMark += sizeClass.nextBlock->capacity();
145 sizeClass.nextBlock = sizeClass.nextBlock->next();
146 sizeClass.currentBlock = 0;
149 for (MarkedBlock*& block = sizeClass.nextBlock ; block; block = block->next()) {
150 firstFreeCell = block->lazySweep();
152 sizeClass.firstFreeCell = firstFreeCell;
153 sizeClass.currentBlock = block;
157 m_waterMark += block->capacity();
164 ASSERT(firstFreeCell);
166 sizeClass.firstFreeCell = firstFreeCell->next;
167 return firstFreeCell;
170 inline void NewSpace::resetPropertyStorageNursery()
172 m_propertyStorageAllocationPoint = m_propertyStorageNursery;
175 inline void* NewSpace::allocatePropertyStorage(size_t size)
177 char* result = m_propertyStorageAllocationPoint;
178 if (size > PropertyStorageNurserySize)
180 m_propertyStorageAllocationPoint += size;
181 if (static_cast<size_t>(m_propertyStorageAllocationPoint - m_propertyStorageNursery) > PropertyStorageNurserySize) {
182 m_propertyStorageAllocationPoint = result;
188 inline bool NewSpace::inPropertyStorageNursery(void* ptr)
190 char* addr = static_cast<char*>(ptr);
191 return static_cast<size_t>(addr - m_propertyStorageNursery) < PropertyStorageNurserySize;
194 template <typename Functor> inline typename Functor::ReturnType NewSpace::forEachBlock(Functor& functor)
196 for (size_t i = 0; i < preciseCount; ++i) {
197 SizeClass& sizeClass = m_preciseSizeClasses[i];
199 for (MarkedBlock* block = sizeClass.blockList.head(); block; block = next) {
200 next = block->next();
205 for (size_t i = 0; i < impreciseCount; ++i) {
206 SizeClass& sizeClass = m_impreciseSizeClasses[i];
208 for (MarkedBlock* block = sizeClass.blockList.head(); block; block = next) {
209 next = block->next();
214 return functor.returnValue();
217 template <typename Functor> inline typename Functor::ReturnType NewSpace::forEachBlock()
220 return forEachBlock(functor);
223 inline NewSpace::SizeClass::SizeClass()
231 inline void NewSpace::SizeClass::resetAllocator()
233 nextBlock = blockList.head();
236 inline void NewSpace::SizeClass::canonicalizeBlock()
239 currentBlock->canonicalizeBlock(firstFreeCell);
243 ASSERT(!firstFreeCell);