]>
Commit | Line | Data |
---|---|---|
1 | /* | |
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. | |
5 | * | |
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. | |
10 | * | |
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. | |
15 | * | |
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 | |
19 | * | |
20 | */ | |
21 | ||
22 | #ifndef Collector_h | |
23 | #define Collector_h | |
24 | ||
25 | #include <stddef.h> | |
26 | #include <string.h> | |
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> | |
33 | ||
34 | #if ENABLE(JSC_MULTIPLE_THREADS) | |
35 | #include <pthread.h> | |
36 | #endif | |
37 | ||
38 | #define ASSERT_CLASS_FITS_IN_CELL(class) COMPILE_ASSERT(sizeof(class) <= CELL_SIZE, class_fits_in_cell) | |
39 | ||
40 | namespace JSC { | |
41 | ||
42 | class CollectorBlock; | |
43 | class JSCell; | |
44 | class JSGlobalData; | |
45 | class JSValue; | |
46 | class MarkedArgumentBuffer; | |
47 | class MarkStack; | |
48 | ||
49 | enum OperationInProgress { NoOperation, Allocation, Collection }; | |
50 | ||
51 | class LiveObjectIterator; | |
52 | ||
53 | struct CollectorHeap { | |
54 | size_t nextBlock; | |
55 | size_t nextCell; | |
56 | CollectorBlock** blocks; | |
57 | ||
58 | void* nextNumber; | |
59 | ||
60 | size_t numBlocks; | |
61 | size_t usedBlocks; | |
62 | ||
63 | size_t extraCost; | |
64 | bool didShrink; | |
65 | ||
66 | OperationInProgress operationInProgress; | |
67 | }; | |
68 | ||
69 | class Heap : public Noncopyable { | |
70 | public: | |
71 | class Thread; | |
72 | ||
73 | void destroy(); | |
74 | ||
75 | void* allocateNumber(size_t); | |
76 | void* allocate(size_t); | |
77 | ||
78 | bool isBusy(); // true if an allocation or collection is in progress | |
79 | void collectAllGarbage(); | |
80 | ||
81 | static const size_t minExtraCost = 256; | |
82 | static const size_t maxExtraCost = 1024 * 1024; | |
83 | ||
84 | void reportExtraMemoryCost(size_t cost); | |
85 | ||
86 | size_t objectCount() const; | |
87 | struct Statistics { | |
88 | size_t size; | |
89 | size_t free; | |
90 | }; | |
91 | Statistics statistics() const; | |
92 | ||
93 | void protect(JSValue); | |
94 | void unprotect(JSValue); | |
95 | ||
96 | static Heap* heap(JSValue); // 0 for immediate values | |
97 | static Heap* heap(JSCell*); | |
98 | ||
99 | size_t globalObjectCount(); | |
100 | size_t protectedObjectCount(); | |
101 | size_t protectedGlobalObjectCount(); | |
102 | HashCountedSet<const char*>* protectedObjectTypeCounts(); | |
103 | ||
104 | void registerThread(); // Only needs to be called by clients that can use the same heap from multiple threads. | |
105 | ||
106 | static bool isCellMarked(const JSCell*); | |
107 | static void markCell(JSCell*); | |
108 | ||
109 | void markConservatively(MarkStack&, void* start, void* end); | |
110 | ||
111 | HashSet<MarkedArgumentBuffer*>& markListSet() { if (!m_markListSet) m_markListSet = new HashSet<MarkedArgumentBuffer*>; return *m_markListSet; } | |
112 | ||
113 | JSGlobalData* globalData() const { return m_globalData; } | |
114 | static bool isNumber(JSCell*); | |
115 | ||
116 | LiveObjectIterator primaryHeapBegin(); | |
117 | LiveObjectIterator primaryHeapEnd(); | |
118 | ||
119 | private: | |
120 | void reset(); | |
121 | void sweep(); | |
122 | static CollectorBlock* cellBlock(const JSCell*); | |
123 | static size_t cellOffset(const JSCell*); | |
124 | ||
125 | friend class JSGlobalData; | |
126 | Heap(JSGlobalData*); | |
127 | ~Heap(); | |
128 | ||
129 | NEVER_INLINE CollectorBlock* allocateBlock(); | |
130 | NEVER_INLINE void freeBlock(size_t); | |
131 | NEVER_INLINE void freeBlockPtr(CollectorBlock*); | |
132 | void freeBlocks(); | |
133 | void resizeBlocks(); | |
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; | |
139 | ||
140 | void recordExtraCost(size_t); | |
141 | ||
142 | void addToStatistics(Statistics&) const; | |
143 | ||
144 | void markRoots(); | |
145 | void markProtectedObjects(MarkStack&); | |
146 | void markCurrentThreadConservatively(MarkStack&); | |
147 | void markCurrentThreadConservativelyInternal(MarkStack&); | |
148 | void markOtherThreadConservatively(MarkStack&, Thread*); | |
149 | void markStackObjectsConservatively(MarkStack&); | |
150 | ||
151 | typedef HashCountedSet<JSCell*> ProtectCountSet; | |
152 | ||
153 | CollectorHeap m_heap; | |
154 | ||
155 | ProtectCountSet m_protectedValues; | |
156 | ||
157 | HashSet<MarkedArgumentBuffer*>* m_markListSet; | |
158 | ||
159 | #if ENABLE(JSC_MULTIPLE_THREADS) | |
160 | void makeUsableFromMultipleThreads(); | |
161 | ||
162 | static void unregisterThread(void*); | |
163 | void unregisterThread(); | |
164 | ||
165 | Mutex m_registeredThreadsMutex; | |
166 | Thread* m_registeredThreads; | |
167 | pthread_key_t m_currentThreadRegistrar; | |
168 | #endif | |
169 | ||
170 | JSGlobalData* m_globalData; | |
171 | }; | |
172 | ||
173 | // tunable parameters | |
174 | template<size_t bytesPerWord> struct CellSize; | |
175 | ||
176 | // cell size needs to be a power of two for certain optimizations in collector.cpp | |
177 | #if USE(JSVALUE32) | |
178 | template<> struct CellSize<sizeof(uint32_t)> { static const size_t m_value = 32; }; | |
179 | #else | |
180 | template<> struct CellSize<sizeof(uint32_t)> { static const size_t m_value = 64; }; | |
181 | #endif | |
182 | template<> struct CellSize<sizeof(uint64_t)> { static const size_t m_value = 64; }; | |
183 | ||
184 | const size_t BLOCK_SIZE = 64 * 1024; // 64k | |
185 | ||
186 | // derived constants | |
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. | |
196 | ||
197 | const size_t BITMAP_SIZE = (CELLS_PER_BLOCK + 7) / 8; | |
198 | const size_t BITMAP_WORDS = (BITMAP_SIZE + 3) / sizeof(uint32_t); | |
199 | ||
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) | |
207 | { | |
208 | size_t result = 0; | |
209 | for ( ; (startCell & 0x1F) != 0; ++startCell) { | |
210 | if (get(startCell)) | |
211 | ++result; | |
212 | } | |
213 | for (size_t i = startCell >> 5; i < BITMAP_WORDS; ++i) | |
214 | result += WTF::bitCount(bits[i]); | |
215 | return result; | |
216 | } | |
217 | size_t isEmpty() // Much more efficient than testing count() == 0. | |
218 | { | |
219 | for (size_t i = 0; i < BITMAP_WORDS; ++i) | |
220 | if (bits[i] != 0) | |
221 | return false; | |
222 | return true; | |
223 | } | |
224 | }; | |
225 | ||
226 | struct CollectorCell { | |
227 | double memory[CELL_ARRAY_LENGTH]; | |
228 | }; | |
229 | ||
230 | class CollectorBlock { | |
231 | public: | |
232 | CollectorCell cells[CELLS_PER_BLOCK]; | |
233 | CollectorBitmap marked; | |
234 | Heap* heap; | |
235 | }; | |
236 | ||
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; | |
242 | }; | |
243 | ||
244 | inline CollectorBlock* Heap::cellBlock(const JSCell* cell) | |
245 | { | |
246 | return reinterpret_cast<CollectorBlock*>(reinterpret_cast<uintptr_t>(cell) & BLOCK_MASK); | |
247 | } | |
248 | ||
249 | inline size_t Heap::cellOffset(const JSCell* cell) | |
250 | { | |
251 | return (reinterpret_cast<uintptr_t>(cell) & BLOCK_OFFSET_MASK) / CELL_SIZE; | |
252 | } | |
253 | ||
254 | inline bool Heap::isCellMarked(const JSCell* cell) | |
255 | { | |
256 | return cellBlock(cell)->marked.get(cellOffset(cell)); | |
257 | } | |
258 | ||
259 | inline void Heap::markCell(JSCell* cell) | |
260 | { | |
261 | cellBlock(cell)->marked.set(cellOffset(cell)); | |
262 | } | |
263 | ||
264 | inline void Heap::reportExtraMemoryCost(size_t cost) | |
265 | { | |
266 | if (cost > minExtraCost) | |
267 | recordExtraCost(cost); | |
268 | } | |
269 | ||
270 | inline void* Heap::allocateNumber(size_t s) | |
271 | { | |
272 | if (void* result = m_heap.nextNumber) { | |
273 | m_heap.nextNumber = 0; | |
274 | return result; | |
275 | } | |
276 | ||
277 | void* result = allocate(s); | |
278 | m_heap.nextNumber = static_cast<char*>(result) + (CELL_SIZE / 2); | |
279 | return result; | |
280 | } | |
281 | ||
282 | } // namespace JSC | |
283 | ||
284 | #endif /* Collector_h */ |