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 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
27 #include <wtf/HashCountedSet.h>
28 #include <wtf/HashSet.h>
29 #include <wtf/Noncopyable.h>
30 #include <wtf/OwnPtr.h>
31 #include <wtf/StdLibExtras.h>
32 #include <wtf/Threading.h>
34 #if ENABLE(JSC_MULTIPLE_THREADS)
38 #define ASSERT_CLASS_FITS_IN_CELL(class) COMPILE_ASSERT(sizeof(class) <= CELL_SIZE, class_fits_in_cell)
46 class MarkedArgumentBuffer
;
49 enum OperationInProgress
{ NoOperation
, Allocation
, Collection
};
51 class LiveObjectIterator
;
53 struct CollectorHeap
{
56 CollectorBlock
** blocks
;
66 OperationInProgress operationInProgress
;
69 class Heap
: public Noncopyable
{
75 void* allocateNumber(size_t);
76 void* allocate(size_t);
78 bool isBusy(); // true if an allocation or collection is in progress
79 void collectAllGarbage();
81 static const size_t minExtraCost
= 256;
82 static const size_t maxExtraCost
= 1024 * 1024;
84 void reportExtraMemoryCost(size_t cost
);
86 size_t objectCount() const;
91 Statistics
statistics() const;
93 void protect(JSValue
);
94 void unprotect(JSValue
);
96 static Heap
* heap(JSValue
); // 0 for immediate values
97 static Heap
* heap(JSCell
*);
99 size_t globalObjectCount();
100 size_t protectedObjectCount();
101 size_t protectedGlobalObjectCount();
102 HashCountedSet
<const char*>* protectedObjectTypeCounts();
104 void registerThread(); // Only needs to be called by clients that can use the same heap from multiple threads.
106 static bool isCellMarked(const JSCell
*);
107 static void markCell(JSCell
*);
109 void markConservatively(MarkStack
&, void* start
, void* end
);
111 HashSet
<MarkedArgumentBuffer
*>& markListSet() { if (!m_markListSet
) m_markListSet
= new HashSet
<MarkedArgumentBuffer
*>; return *m_markListSet
; }
113 JSGlobalData
* globalData() const { return m_globalData
; }
114 static bool isNumber(JSCell
*);
116 LiveObjectIterator
primaryHeapBegin();
117 LiveObjectIterator
primaryHeapEnd();
122 static CollectorBlock
* cellBlock(const JSCell
*);
123 static size_t cellOffset(const JSCell
*);
125 friend class JSGlobalData
;
129 NEVER_INLINE CollectorBlock
* allocateBlock();
130 NEVER_INLINE
void freeBlock(size_t);
131 NEVER_INLINE
void freeBlockPtr(CollectorBlock
*);
134 void growBlocks(size_t neededBlocks
);
135 void shrinkBlocks(size_t neededBlocks
);
136 void clearMarkBits();
137 void clearMarkBits(CollectorBlock
*);
138 size_t markedCells(size_t startBlock
= 0, size_t startCell
= 0) const;
140 void recordExtraCost(size_t);
142 void addToStatistics(Statistics
&) const;
145 void markProtectedObjects(MarkStack
&);
146 void markCurrentThreadConservatively(MarkStack
&);
147 void markCurrentThreadConservativelyInternal(MarkStack
&);
148 void markOtherThreadConservatively(MarkStack
&, Thread
*);
149 void markStackObjectsConservatively(MarkStack
&);
151 typedef HashCountedSet
<JSCell
*> ProtectCountSet
;
153 CollectorHeap m_heap
;
155 ProtectCountSet m_protectedValues
;
157 HashSet
<MarkedArgumentBuffer
*>* m_markListSet
;
159 #if ENABLE(JSC_MULTIPLE_THREADS)
160 void makeUsableFromMultipleThreads();
162 static void unregisterThread(void*);
163 void unregisterThread();
165 Mutex m_registeredThreadsMutex
;
166 Thread
* m_registeredThreads
;
167 pthread_key_t m_currentThreadRegistrar
;
170 JSGlobalData
* m_globalData
;
173 // tunable parameters
174 template<size_t bytesPerWord
> struct CellSize
;
176 // cell size needs to be a power of two for certain optimizations in collector.cpp
178 template<> struct CellSize
<sizeof(uint32_t)> { static const size_t m_value
= 32; };
180 template<> struct CellSize
<sizeof(uint32_t)> { static const size_t m_value
= 64; };
182 template<> struct CellSize
<sizeof(uint64_t)> { static const size_t m_value
= 64; };
184 const size_t BLOCK_SIZE
= 64 * 1024; // 64k
187 const size_t BLOCK_OFFSET_MASK
= BLOCK_SIZE
- 1;
188 const size_t BLOCK_MASK
= ~BLOCK_OFFSET_MASK
;
189 const size_t MINIMUM_CELL_SIZE
= CellSize
<sizeof(void*)>::m_value
;
190 const size_t CELL_ARRAY_LENGTH
= (MINIMUM_CELL_SIZE
/ sizeof(double)) + (MINIMUM_CELL_SIZE
% sizeof(double) != 0 ? sizeof(double) : 0);
191 const size_t CELL_SIZE
= CELL_ARRAY_LENGTH
* sizeof(double);
192 const size_t SMALL_CELL_SIZE
= CELL_SIZE
/ 2;
193 const size_t CELL_MASK
= CELL_SIZE
- 1;
194 const size_t CELL_ALIGN_MASK
= ~CELL_MASK
;
195 const size_t CELLS_PER_BLOCK
= (BLOCK_SIZE
- sizeof(Heap
*)) * 8 * CELL_SIZE
/ (8 * CELL_SIZE
+ 1) / CELL_SIZE
; // one bitmap byte can represent 8 cells.
197 const size_t BITMAP_SIZE
= (CELLS_PER_BLOCK
+ 7) / 8;
198 const size_t BITMAP_WORDS
= (BITMAP_SIZE
+ 3) / sizeof(uint32_t);
200 struct CollectorBitmap
{
201 uint32_t bits
[BITMAP_WORDS
];
202 bool get(size_t n
) const { return !!(bits
[n
>> 5] & (1 << (n
& 0x1F))); }
203 void set(size_t n
) { bits
[n
>> 5] |= (1 << (n
& 0x1F)); }
204 void clear(size_t n
) { bits
[n
>> 5] &= ~(1 << (n
& 0x1F)); }
205 void clearAll() { memset(bits
, 0, sizeof(bits
)); }
206 size_t count(size_t startCell
= 0)
209 for ( ; (startCell
& 0x1F) != 0; ++startCell
) {
213 for (size_t i
= startCell
>> 5; i
< BITMAP_WORDS
; ++i
)
214 result
+= WTF::bitCount(bits
[i
]);
217 size_t isEmpty() // Much more efficient than testing count() == 0.
219 for (size_t i
= 0; i
< BITMAP_WORDS
; ++i
)
226 struct CollectorCell
{
227 double memory
[CELL_ARRAY_LENGTH
];
230 class CollectorBlock
{
232 CollectorCell cells
[CELLS_PER_BLOCK
];
233 CollectorBitmap marked
;
237 struct HeapConstants
{
238 static const size_t cellSize
= CELL_SIZE
;
239 static const size_t cellsPerBlock
= CELLS_PER_BLOCK
;
240 typedef CollectorCell Cell
;
241 typedef CollectorBlock Block
;
244 inline CollectorBlock
* Heap::cellBlock(const JSCell
* cell
)
246 return reinterpret_cast<CollectorBlock
*>(reinterpret_cast<uintptr_t>(cell
) & BLOCK_MASK
);
249 inline size_t Heap::cellOffset(const JSCell
* cell
)
251 return (reinterpret_cast<uintptr_t>(cell
) & BLOCK_OFFSET_MASK
) / CELL_SIZE
;
254 inline bool Heap::isCellMarked(const JSCell
* cell
)
256 return cellBlock(cell
)->marked
.get(cellOffset(cell
));
259 inline void Heap::markCell(JSCell
* cell
)
261 cellBlock(cell
)->marked
.set(cellOffset(cell
));
264 inline void Heap::reportExtraMemoryCost(size_t cost
)
266 if (cost
> minExtraCost
)
267 recordExtraCost(cost
);
270 inline void* Heap::allocateNumber(size_t s
)
272 if (void* result
= m_heap
.nextNumber
) {
273 m_heap
.nextNumber
= 0;
277 void* result
= allocate(s
);
278 m_heap
.nextNumber
= static_cast<char*>(result
) + (CELL_SIZE
/ 2);
284 #endif /* Collector_h */