]>
Commit | Line | Data |
---|---|---|
14957cd0 A |
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 Heap_h | |
23 | #define Heap_h | |
24 | ||
6fe7ccc8 A |
25 | #include "BlockAllocator.h" |
26 | #include "DFGCodeBlocks.h" | |
27 | #include "HandleSet.h" | |
14957cd0 | 28 | #include "HandleStack.h" |
6fe7ccc8 A |
29 | #include "MarkedAllocator.h" |
30 | #include "MarkedBlock.h" | |
31 | #include "MarkedBlockSet.h" | |
14957cd0 | 32 | #include "MarkedSpace.h" |
6fe7ccc8 A |
33 | #include "SlotVisitor.h" |
34 | #include "WeakHandleOwner.h" | |
35 | #include "WeakSet.h" | |
36 | #include "WriteBarrierSupport.h" | |
14957cd0 A |
37 | #include <wtf/HashCountedSet.h> |
38 | #include <wtf/HashSet.h> | |
39 | ||
6fe7ccc8 A |
40 | #define COLLECT_ON_EVERY_ALLOCATION 0 |
41 | ||
14957cd0 A |
42 | namespace JSC { |
43 | ||
6fe7ccc8 A |
44 | class CopiedSpace; |
45 | class CodeBlock; | |
46 | class FunctionExecutable; | |
14957cd0 A |
47 | class GCActivityCallback; |
48 | class GlobalCodeBlock; | |
6fe7ccc8 | 49 | class Heap; |
14957cd0 A |
50 | class HeapRootVisitor; |
51 | class JSCell; | |
52 | class JSGlobalData; | |
53 | class JSValue; | |
54 | class LiveObjectIterator; | |
6fe7ccc8 | 55 | class LLIntOffsetsExtractor; |
14957cd0 A |
56 | class MarkedArgumentBuffer; |
57 | class RegisterFile; | |
58 | class UString; | |
59 | class WeakGCHandlePool; | |
6fe7ccc8 | 60 | class SlotVisitor; |
14957cd0 A |
61 | |
62 | typedef std::pair<JSValue, UString> ValueStringPair; | |
63 | typedef HashCountedSet<JSCell*> ProtectCountSet; | |
64 | typedef HashCountedSet<const char*> TypeCountSet; | |
65 | ||
66 | enum OperationInProgress { NoOperation, Allocation, Collection }; | |
67 | ||
6fe7ccc8 A |
68 | // Heap size hint. |
69 | enum HeapSize { SmallHeap, LargeHeap }; | |
70 | ||
14957cd0 A |
71 | class Heap { |
72 | WTF_MAKE_NONCOPYABLE(Heap); | |
73 | public: | |
6fe7ccc8 A |
74 | friend class JIT; |
75 | friend class MarkStackThreadSharedData; | |
76 | static Heap* heap(const JSValue); // 0 for immediate values | |
77 | static Heap* heap(const JSCell*); | |
78 | ||
79 | // This constant determines how many blocks we iterate between checks of our | |
80 | // deadline when calling Heap::isPagedOut. Decreasing it will cause us to detect | |
81 | // overstepping our deadline more quickly, while increasing it will cause | |
82 | // our scan to run faster. | |
83 | static const unsigned s_timeCheckResolution = 16; | |
14957cd0 | 84 | |
6fe7ccc8 A |
85 | static bool isMarked(const void*); |
86 | static bool testAndSetMarked(const void*); | |
87 | static void setMarked(const void*); | |
14957cd0 A |
88 | |
89 | static void writeBarrier(const JSCell*, JSValue); | |
90 | static void writeBarrier(const JSCell*, JSCell*); | |
6fe7ccc8 | 91 | static uint8_t* addressOfCardFor(JSCell*); |
14957cd0 | 92 | |
6fe7ccc8 | 93 | Heap(JSGlobalData*, HeapSize); |
14957cd0 | 94 | ~Heap(); |
6fe7ccc8 | 95 | JS_EXPORT_PRIVATE void lastChanceToFinalize(); |
14957cd0 A |
96 | |
97 | JSGlobalData* globalData() const { return m_globalData; } | |
6fe7ccc8 | 98 | MarkedSpace& objectSpace() { return m_objectSpace; } |
14957cd0 A |
99 | MachineThreads& machineThreads() { return m_machineThreads; } |
100 | ||
6fe7ccc8 A |
101 | JS_EXPORT_PRIVATE GCActivityCallback* activityCallback(); |
102 | JS_EXPORT_PRIVATE void setActivityCallback(GCActivityCallback*); | |
14957cd0 A |
103 | |
104 | // true if an allocation or collection is in progress | |
105 | inline bool isBusy(); | |
6fe7ccc8 A |
106 | |
107 | MarkedAllocator& firstAllocatorWithoutDestructors() { return m_objectSpace.firstAllocator(); } | |
108 | MarkedAllocator& allocatorForObjectWithoutDestructor(size_t bytes) { return m_objectSpace.allocatorFor(bytes); } | |
109 | MarkedAllocator& allocatorForObjectWithDestructor(size_t bytes) { return m_objectSpace.destructorAllocatorFor(bytes); } | |
110 | CopiedAllocator& storageAllocator() { return m_storageSpace.allocator(); } | |
111 | CheckedBoolean tryAllocateStorage(size_t, void**); | |
112 | CheckedBoolean tryReallocateStorage(void**, size_t, size_t); | |
14957cd0 | 113 | |
6fe7ccc8 A |
114 | typedef void (*Finalizer)(JSCell*); |
115 | JS_EXPORT_PRIVATE void addFinalizer(JSCell*, Finalizer); | |
116 | void addFunctionExecutable(FunctionExecutable*); | |
117 | void removeFunctionExecutable(FunctionExecutable*); | |
14957cd0 | 118 | |
6fe7ccc8 | 119 | void notifyIsSafeToCollect() { m_isSafeToCollect = true; } |
14957cd0 | 120 | |
6fe7ccc8 A |
121 | JS_EXPORT_PRIVATE void collectAllGarbage(); |
122 | enum SweepToggle { DoNotSweep, DoSweep }; | |
123 | bool shouldCollect(); | |
124 | void collect(SweepToggle); | |
125 | ||
126 | void reportExtraMemoryCost(size_t cost); | |
127 | JS_EXPORT_PRIVATE void reportAbandonedObjectGraph(); | |
14957cd0 | 128 | |
6fe7ccc8 A |
129 | JS_EXPORT_PRIVATE void protect(JSValue); |
130 | JS_EXPORT_PRIVATE bool unprotect(JSValue); // True when the protect count drops to 0. | |
131 | ||
132 | void jettisonDFGCodeBlock(PassOwnPtr<CodeBlock>); | |
14957cd0 | 133 | |
6fe7ccc8 A |
134 | JS_EXPORT_PRIVATE size_t size(); |
135 | JS_EXPORT_PRIVATE size_t capacity(); | |
136 | JS_EXPORT_PRIVATE size_t objectCount(); | |
137 | JS_EXPORT_PRIVATE size_t globalObjectCount(); | |
138 | JS_EXPORT_PRIVATE size_t protectedObjectCount(); | |
139 | JS_EXPORT_PRIVATE size_t protectedGlobalObjectCount(); | |
140 | JS_EXPORT_PRIVATE PassOwnPtr<TypeCountSet> protectedObjectTypeCounts(); | |
141 | JS_EXPORT_PRIVATE PassOwnPtr<TypeCountSet> objectTypeCounts(); | |
14957cd0 A |
142 | |
143 | void pushTempSortVector(Vector<ValueStringPair>*); | |
144 | void popTempSortVector(Vector<ValueStringPair>*); | |
145 | ||
146 | HashSet<MarkedArgumentBuffer*>& markListSet() { if (!m_markListSet) m_markListSet = new HashSet<MarkedArgumentBuffer*>; return *m_markListSet; } | |
147 | ||
6fe7ccc8 A |
148 | template<typename Functor> typename Functor::ReturnType forEachProtectedCell(Functor&); |
149 | template<typename Functor> typename Functor::ReturnType forEachProtectedCell(); | |
14957cd0 | 150 | |
6fe7ccc8 A |
151 | WeakSet* weakSet() { return &m_weakSet; } |
152 | HandleSet* handleSet() { return &m_handleSet; } | |
14957cd0 | 153 | HandleStack* handleStack() { return &m_handleStack; } |
6fe7ccc8 | 154 | |
14957cd0 A |
155 | void getConservativeRegisterRoots(HashSet<JSCell*>& roots); |
156 | ||
6fe7ccc8 A |
157 | double lastGCLength() { return m_lastGCLength; } |
158 | void increaseLastGCLength(double amount) { m_lastGCLength += amount; } | |
159 | ||
160 | JS_EXPORT_PRIVATE void discardAllCompiledCode(); | |
161 | ||
162 | void didAllocate(size_t); | |
163 | void didAbandon(size_t); | |
164 | ||
165 | bool isPagedOut(double deadline); | |
166 | ||
14957cd0 | 167 | private: |
6fe7ccc8 A |
168 | friend class CodeBlock; |
169 | friend class LLIntOffsetsExtractor; | |
170 | friend class MarkedSpace; | |
171 | friend class MarkedAllocator; | |
172 | friend class MarkedBlock; | |
173 | friend class CopiedSpace; | |
174 | friend class SlotVisitor; | |
175 | template<typename T> friend void* allocateCell(Heap&); | |
176 | ||
177 | void* allocateWithDestructor(size_t); | |
178 | void* allocateWithoutDestructor(size_t); | |
14957cd0 A |
179 | |
180 | static const size_t minExtraCost = 256; | |
181 | static const size_t maxExtraCost = 1024 * 1024; | |
6fe7ccc8 A |
182 | |
183 | class FinalizerOwner : public WeakHandleOwner { | |
184 | virtual void finalize(Handle<Unknown>, void* context); | |
185 | }; | |
186 | ||
187 | JS_EXPORT_PRIVATE bool isValidAllocation(size_t); | |
188 | JS_EXPORT_PRIVATE void reportExtraMemoryCostSlowCase(size_t); | |
189 | ||
190 | // Call this function before any operation that needs to know which cells | |
191 | // in the heap are live. (For example, call this function before | |
192 | // conservative marking, eager sweeping, or iterating the cells in a MarkedBlock.) | |
193 | void canonicalizeCellLivenessData(); | |
14957cd0 | 194 | |
6fe7ccc8 | 195 | void resetAllocators(); |
14957cd0 | 196 | |
6fe7ccc8 A |
197 | void clearMarks(); |
198 | void markRoots(bool fullGC); | |
14957cd0 A |
199 | void markProtectedObjects(HeapRootVisitor&); |
200 | void markTempSortVectors(HeapRootVisitor&); | |
6fe7ccc8 A |
201 | void harvestWeakReferences(); |
202 | void finalizeUnconditionalFinalizers(); | |
203 | ||
204 | void sweep(); | |
14957cd0 A |
205 | |
206 | RegisterFile& registerFile(); | |
6fe7ccc8 | 207 | BlockAllocator& blockAllocator(); |
14957cd0 | 208 | |
6fe7ccc8 A |
209 | const HeapSize m_heapSize; |
210 | const size_t m_minBytesPerCycle; | |
211 | size_t m_sizeAfterLastCollect; | |
212 | ||
213 | size_t m_bytesAllocatedLimit; | |
214 | size_t m_bytesAllocated; | |
215 | size_t m_bytesAbandoned; | |
216 | ||
14957cd0 | 217 | OperationInProgress m_operationInProgress; |
6fe7ccc8 A |
218 | MarkedSpace m_objectSpace; |
219 | CopiedSpace m_storageSpace; | |
220 | ||
221 | BlockAllocator m_blockAllocator; | |
222 | ||
223 | #if ENABLE(SIMPLE_HEAP_PROFILING) | |
224 | VTableSpectrum m_destroyedTypeCounts; | |
225 | #endif | |
14957cd0 A |
226 | |
227 | ProtectCountSet m_protectedValues; | |
228 | Vector<Vector<ValueStringPair>* > m_tempSortingVectors; | |
14957cd0 A |
229 | HashSet<MarkedArgumentBuffer*>* m_markListSet; |
230 | ||
14957cd0 | 231 | MachineThreads m_machineThreads; |
6fe7ccc8 A |
232 | |
233 | MarkStackThreadSharedData m_sharedData; | |
234 | SlotVisitor m_slotVisitor; | |
235 | ||
236 | WeakSet m_weakSet; | |
237 | HandleSet m_handleSet; | |
14957cd0 | 238 | HandleStack m_handleStack; |
6fe7ccc8 A |
239 | DFGCodeBlocks m_dfgCodeBlocks; |
240 | FinalizerOwner m_finalizerOwner; | |
241 | ||
242 | bool m_isSafeToCollect; | |
14957cd0 | 243 | |
6fe7ccc8 A |
244 | JSGlobalData* m_globalData; |
245 | double m_lastGCLength; | |
246 | double m_lastCodeDiscardTime; | |
247 | ||
248 | DoublyLinkedList<FunctionExecutable> m_functions; | |
249 | ||
250 | GCActivityCallback* m_activityCallback; | |
14957cd0 A |
251 | }; |
252 | ||
6fe7ccc8 A |
253 | inline bool Heap::shouldCollect() |
254 | { | |
255 | #if ENABLE(GGC) | |
256 | return m_objectSpace.nurseryWaterMark() >= m_minBytesPerCycle && m_isSafeToCollect && m_operationInProgress == NoOperation; | |
257 | #else | |
258 | return m_bytesAllocated > m_bytesAllocatedLimit && m_isSafeToCollect && m_operationInProgress == NoOperation; | |
259 | #endif | |
260 | } | |
261 | ||
14957cd0 A |
262 | bool Heap::isBusy() |
263 | { | |
264 | return m_operationInProgress != NoOperation; | |
265 | } | |
266 | ||
6fe7ccc8 | 267 | inline Heap* Heap::heap(const JSCell* cell) |
14957cd0 | 268 | { |
6fe7ccc8 | 269 | return MarkedBlock::blockFor(cell)->heap(); |
14957cd0 A |
270 | } |
271 | ||
6fe7ccc8 | 272 | inline Heap* Heap::heap(const JSValue v) |
14957cd0 | 273 | { |
6fe7ccc8 A |
274 | if (!v.isCell()) |
275 | return 0; | |
276 | return heap(v.asCell()); | |
14957cd0 A |
277 | } |
278 | ||
6fe7ccc8 | 279 | inline bool Heap::isMarked(const void* cell) |
14957cd0 | 280 | { |
6fe7ccc8 | 281 | return MarkedBlock::blockFor(cell)->isMarked(cell); |
14957cd0 A |
282 | } |
283 | ||
6fe7ccc8 A |
284 | inline bool Heap::testAndSetMarked(const void* cell) |
285 | { | |
286 | return MarkedBlock::blockFor(cell)->testAndSetMarked(cell); | |
287 | } | |
288 | ||
289 | inline void Heap::setMarked(const void* cell) | |
290 | { | |
291 | MarkedBlock::blockFor(cell)->setMarked(cell); | |
292 | } | |
293 | ||
294 | #if ENABLE(GGC) | |
295 | inline uint8_t* Heap::addressOfCardFor(JSCell* cell) | |
14957cd0 | 296 | { |
6fe7ccc8 | 297 | return MarkedBlock::blockFor(cell)->addressOfCardFor(cell); |
14957cd0 A |
298 | } |
299 | ||
6fe7ccc8 A |
300 | inline void Heap::writeBarrier(const JSCell* owner, JSCell*) |
301 | { | |
302 | WriteBarrierCounters::countWriteBarrier(); | |
303 | MarkedBlock* block = MarkedBlock::blockFor(owner); | |
304 | if (block->isMarked(owner)) | |
305 | block->setDirtyObject(owner); | |
306 | } | |
307 | ||
308 | inline void Heap::writeBarrier(const JSCell* owner, JSValue value) | |
309 | { | |
310 | if (!value) | |
311 | return; | |
312 | if (!value.isCell()) | |
313 | return; | |
314 | writeBarrier(owner, value.asCell()); | |
315 | } | |
316 | #else | |
317 | ||
14957cd0 A |
318 | inline void Heap::writeBarrier(const JSCell*, JSCell*) |
319 | { | |
6fe7ccc8 | 320 | WriteBarrierCounters::countWriteBarrier(); |
14957cd0 A |
321 | } |
322 | ||
6fe7ccc8 | 323 | inline void Heap::writeBarrier(const JSCell*, JSValue) |
14957cd0 | 324 | { |
6fe7ccc8 | 325 | WriteBarrierCounters::countWriteBarrier(); |
14957cd0 | 326 | } |
6fe7ccc8 | 327 | #endif |
14957cd0 A |
328 | |
329 | inline void Heap::reportExtraMemoryCost(size_t cost) | |
330 | { | |
331 | if (cost > minExtraCost) | |
332 | reportExtraMemoryCostSlowCase(cost); | |
333 | } | |
334 | ||
6fe7ccc8 A |
335 | template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell(Functor& functor) |
336 | { | |
337 | ProtectCountSet::iterator end = m_protectedValues.end(); | |
338 | for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) | |
339 | functor(it->first); | |
340 | m_handleSet.forEachStrongHandle(functor, m_protectedValues); | |
341 | ||
342 | return functor.returnValue(); | |
343 | } | |
344 | ||
345 | template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell() | |
346 | { | |
347 | Functor functor; | |
348 | return forEachProtectedCell(functor); | |
349 | } | |
350 | ||
351 | inline void* Heap::allocateWithDestructor(size_t bytes) | |
352 | { | |
353 | ASSERT(isValidAllocation(bytes)); | |
354 | return m_objectSpace.allocateWithDestructor(bytes); | |
355 | } | |
356 | ||
357 | inline void* Heap::allocateWithoutDestructor(size_t bytes) | |
358 | { | |
359 | ASSERT(isValidAllocation(bytes)); | |
360 | return m_objectSpace.allocateWithoutDestructor(bytes); | |
361 | } | |
362 | ||
363 | inline CheckedBoolean Heap::tryAllocateStorage(size_t bytes, void** outPtr) | |
364 | { | |
365 | return m_storageSpace.tryAllocate(bytes, outPtr); | |
366 | } | |
367 | ||
368 | inline CheckedBoolean Heap::tryReallocateStorage(void** ptr, size_t oldSize, size_t newSize) | |
369 | { | |
370 | return m_storageSpace.tryReallocate(ptr, oldSize, newSize); | |
371 | } | |
372 | ||
373 | inline BlockAllocator& Heap::blockAllocator() | |
14957cd0 | 374 | { |
6fe7ccc8 | 375 | return m_blockAllocator; |
14957cd0 A |
376 | } |
377 | ||
378 | } // namespace JSC | |
379 | ||
380 | #endif // Heap_h |