]>
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) | |
81345200 | 4 | * Copyright (C) 2003-2009, 2013-2014 Apple Inc. All rights reserved. |
14957cd0 A |
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 | ||
81345200 | 25 | #include "ArrayBuffer.h" |
81345200 | 26 | #include "CodeBlockSet.h" |
93a37866 | 27 | #include "CopyVisitor.h" |
81345200 | 28 | #include "GCIncomingRefCountedSet.h" |
93a37866 | 29 | #include "GCThreadSharedData.h" |
6fe7ccc8 | 30 | #include "HandleSet.h" |
14957cd0 | 31 | #include "HandleStack.h" |
81345200 | 32 | #include "HeapOperation.h" |
93a37866 | 33 | #include "JITStubRoutineSet.h" |
6fe7ccc8 A |
34 | #include "MarkedAllocator.h" |
35 | #include "MarkedBlock.h" | |
36 | #include "MarkedBlockSet.h" | |
14957cd0 | 37 | #include "MarkedSpace.h" |
93a37866 | 38 | #include "Options.h" |
6fe7ccc8 | 39 | #include "SlotVisitor.h" |
81345200 | 40 | #include "StructureIDTable.h" |
6fe7ccc8 | 41 | #include "WeakHandleOwner.h" |
81345200 | 42 | #include "WriteBarrierBuffer.h" |
6fe7ccc8 | 43 | #include "WriteBarrierSupport.h" |
14957cd0 A |
44 | #include <wtf/HashCountedSet.h> |
45 | #include <wtf/HashSet.h> | |
46 | ||
47 | namespace JSC { | |
48 | ||
81345200 A |
49 | class CopiedSpace; |
50 | class CodeBlock; | |
51 | class ExecutableBase; | |
52 | class EdenGCActivityCallback; | |
53 | class FullGCActivityCallback; | |
54 | class GCActivityCallback; | |
55 | class GCAwareJITStubRoutine; | |
56 | class GlobalCodeBlock; | |
57 | class Heap; | |
58 | class HeapRootVisitor; | |
ed1e77d3 | 59 | class HeapVerifier; |
81345200 A |
60 | class IncrementalSweeper; |
61 | class JITStubRoutine; | |
62 | class JSCell; | |
63 | class VM; | |
64 | class JSStack; | |
65 | class JSValue; | |
66 | class LiveObjectIterator; | |
67 | class LLIntOffsetsExtractor; | |
68 | class MarkedArgumentBuffer; | |
69 | class WeakGCHandlePool; | |
70 | class SlotVisitor; | |
71 | ||
72 | namespace DFG { | |
73 | class Worklist; | |
74 | } | |
75 | ||
76 | static void* const zombifiedBits = reinterpret_cast<void*>(0xdeadbeef); | |
77 | ||
81345200 A |
78 | typedef HashCountedSet<JSCell*> ProtectCountSet; |
79 | typedef HashCountedSet<const char*> TypeCountSet; | |
80 | ||
81 | enum HeapType { SmallHeap, LargeHeap }; | |
82 | ||
83 | class Heap { | |
84 | WTF_MAKE_NONCOPYABLE(Heap); | |
85 | public: | |
86 | friend class JIT; | |
87 | friend class DFG::SpeculativeJIT; | |
88 | friend class GCThreadSharedData; | |
89 | static Heap* heap(const JSValue); // 0 for immediate values | |
90 | static Heap* heap(const JSCell*); | |
91 | ||
92 | // This constant determines how many blocks we iterate between checks of our | |
93 | // deadline when calling Heap::isPagedOut. Decreasing it will cause us to detect | |
94 | // overstepping our deadline more quickly, while increasing it will cause | |
95 | // our scan to run faster. | |
96 | static const unsigned s_timeCheckResolution = 16; | |
97 | ||
98 | static bool isLive(const void*); | |
99 | static bool isMarked(const void*); | |
100 | static bool testAndSetMarked(const void*); | |
101 | static void setMarked(const void*); | |
102 | static bool isRemembered(const void*); | |
103 | ||
104 | JS_EXPORT_PRIVATE void addToRememberedSet(const JSCell*); | |
105 | static bool isWriteBarrierEnabled(); | |
106 | void writeBarrier(const JSCell*); | |
107 | void writeBarrier(const JSCell*, JSValue); | |
108 | void writeBarrier(const JSCell*, JSCell*); | |
109 | ||
110 | WriteBarrierBuffer& writeBarrierBuffer() { return m_writeBarrierBuffer; } | |
111 | void flushWriteBarrierBuffer(JSCell*); | |
112 | ||
113 | Heap(VM*, HeapType); | |
114 | ~Heap(); | |
115 | JS_EXPORT_PRIVATE void lastChanceToFinalize(); | |
ed1e77d3 | 116 | void releaseDelayedReleasedObjects(); |
81345200 A |
117 | |
118 | VM* vm() const { return m_vm; } | |
119 | MarkedSpace& objectSpace() { return m_objectSpace; } | |
ed1e77d3 | 120 | CopiedSpace& storageSpace() { return m_storageSpace; } |
81345200 A |
121 | MachineThreads& machineThreads() { return m_machineThreads; } |
122 | ||
123 | const SlotVisitor& slotVisitor() const { return m_slotVisitor; } | |
124 | ||
125 | JS_EXPORT_PRIVATE GCActivityCallback* fullActivityCallback(); | |
126 | JS_EXPORT_PRIVATE GCActivityCallback* edenActivityCallback(); | |
127 | JS_EXPORT_PRIVATE void setFullActivityCallback(PassRefPtr<FullGCActivityCallback>); | |
128 | JS_EXPORT_PRIVATE void setEdenActivityCallback(PassRefPtr<EdenGCActivityCallback>); | |
129 | JS_EXPORT_PRIVATE void setGarbageCollectionTimerEnabled(bool); | |
130 | ||
131 | JS_EXPORT_PRIVATE IncrementalSweeper* sweeper(); | |
ed1e77d3 | 132 | JS_EXPORT_PRIVATE void setIncrementalSweeper(std::unique_ptr<IncrementalSweeper>); |
81345200 A |
133 | |
134 | // true if collection is in progress | |
135 | bool isCollecting(); | |
136 | HeapOperation operationInProgress() { return m_operationInProgress; } | |
137 | // true if an allocation or collection is in progress | |
138 | bool isBusy(); | |
ed1e77d3 A |
139 | MarkedSpace::Subspace& subspaceForObjectWithoutDestructor() { return m_objectSpace.subspaceForObjectsWithoutDestructor(); } |
140 | MarkedSpace::Subspace& subspaceForObjectDestructor() { return m_objectSpace.subspaceForObjectsWithDestructor(); } | |
141 | template<typename ClassType> MarkedSpace::Subspace& subspaceForObjectOfType(); | |
81345200 | 142 | MarkedAllocator& allocatorForObjectWithoutDestructor(size_t bytes) { return m_objectSpace.allocatorFor(bytes); } |
ed1e77d3 A |
143 | MarkedAllocator& allocatorForObjectWithDestructor(size_t bytes) { return m_objectSpace.destructorAllocatorFor(bytes); } |
144 | template<typename ClassType> MarkedAllocator& allocatorForObjectOfType(size_t bytes); | |
81345200 A |
145 | CopiedAllocator& storageAllocator() { return m_storageSpace.allocator(); } |
146 | CheckedBoolean tryAllocateStorage(JSCell* intendedOwner, size_t, void**); | |
147 | CheckedBoolean tryReallocateStorage(JSCell* intendedOwner, void**, size_t, size_t); | |
148 | void ascribeOwner(JSCell* intendedOwner, void*); | |
149 | ||
150 | typedef void (*Finalizer)(JSCell*); | |
151 | JS_EXPORT_PRIVATE void addFinalizer(JSCell*, Finalizer); | |
152 | void addCompiledCode(ExecutableBase*); | |
153 | ||
154 | void notifyIsSafeToCollect() { m_isSafeToCollect = true; } | |
155 | bool isSafeToCollect() const { return m_isSafeToCollect; } | |
156 | ||
ed1e77d3 A |
157 | JS_EXPORT_PRIVATE void collectAllGarbageIfNotDoneRecently(); |
158 | void collectAllGarbage() { collectAndSweep(FullCollection); } | |
159 | JS_EXPORT_PRIVATE void collectAndSweep(HeapOperation collectionType = AnyCollection); | |
81345200 A |
160 | bool shouldCollect(); |
161 | JS_EXPORT_PRIVATE void collect(HeapOperation collectionType = AnyCollection); | |
162 | bool collectIfNecessaryOrDefer(); // Returns true if it did collect. | |
163 | ||
ed1e77d3 A |
164 | // Use this API to report non-GC memory referenced by GC objects. Be sure to |
165 | // call both of these functions: Calling only one may trigger catastropic | |
166 | // memory growth. | |
167 | void reportExtraMemoryAllocated(size_t); | |
168 | void reportExtraMemoryVisited(JSCell*, size_t); | |
169 | ||
170 | // Use this API to report non-GC memory if you can't use the better API above. | |
171 | void deprecatedReportExtraMemory(size_t); | |
172 | ||
81345200 A |
173 | JS_EXPORT_PRIVATE void reportAbandonedObjectGraph(); |
174 | ||
175 | JS_EXPORT_PRIVATE void protect(JSValue); | |
176 | JS_EXPORT_PRIVATE bool unprotect(JSValue); // True when the protect count drops to 0. | |
177 | ||
ed1e77d3 | 178 | size_t extraMemorySize(); // Non-GC memory referenced by GC objects. |
81345200 A |
179 | JS_EXPORT_PRIVATE size_t size(); |
180 | JS_EXPORT_PRIVATE size_t capacity(); | |
181 | JS_EXPORT_PRIVATE size_t objectCount(); | |
182 | JS_EXPORT_PRIVATE size_t globalObjectCount(); | |
183 | JS_EXPORT_PRIVATE size_t protectedObjectCount(); | |
184 | JS_EXPORT_PRIVATE size_t protectedGlobalObjectCount(); | |
ed1e77d3 A |
185 | JS_EXPORT_PRIVATE std::unique_ptr<TypeCountSet> protectedObjectTypeCounts(); |
186 | JS_EXPORT_PRIVATE std::unique_ptr<TypeCountSet> objectTypeCounts(); | |
81345200 A |
187 | void showStatistics(); |
188 | ||
81345200 A |
189 | HashSet<MarkedArgumentBuffer*>& markListSet(); |
190 | ||
191 | template<typename Functor> typename Functor::ReturnType forEachProtectedCell(Functor&); | |
192 | template<typename Functor> typename Functor::ReturnType forEachProtectedCell(); | |
193 | template<typename Functor> void forEachCodeBlock(Functor&); | |
194 | ||
195 | HandleSet* handleSet() { return &m_handleSet; } | |
196 | HandleStack* handleStack() { return &m_handleStack; } | |
197 | ||
198 | void willStartIterating(); | |
199 | void didFinishIterating(); | |
200 | void getConservativeRegisterRoots(HashSet<JSCell*>& roots); | |
201 | ||
202 | double lastFullGCLength() const { return m_lastFullGCLength; } | |
203 | double lastEdenGCLength() const { return m_lastEdenGCLength; } | |
204 | void increaseLastFullGCLength(double amount) { m_lastFullGCLength += amount; } | |
205 | ||
206 | size_t sizeBeforeLastEdenCollection() const { return m_sizeBeforeLastEdenCollect; } | |
207 | size_t sizeAfterLastEdenCollection() const { return m_sizeAfterLastEdenCollect; } | |
208 | size_t sizeBeforeLastFullCollection() const { return m_sizeBeforeLastFullCollect; } | |
209 | size_t sizeAfterLastFullCollection() const { return m_sizeAfterLastFullCollect; } | |
210 | ||
211 | JS_EXPORT_PRIVATE void deleteAllCompiledCode(); | |
212 | void deleteAllUnlinkedFunctionCode(); | |
213 | ||
214 | void didAllocate(size_t); | |
215 | void didAbandon(size_t); | |
216 | ||
217 | bool isPagedOut(double deadline); | |
218 | ||
219 | const JITStubRoutineSet& jitStubRoutines() { return m_jitStubRoutines; } | |
14957cd0 | 220 | |
81345200 A |
221 | void addReference(JSCell*, ArrayBuffer*); |
222 | ||
223 | bool isDeferred() const { return !!m_deferralDepth || Options::disableGC(); } | |
224 | ||
81345200 A |
225 | StructureIDTable& structureIDTable() { return m_structureIDTable; } |
226 | ||
227 | #if USE(CF) | |
228 | template<typename T> void releaseSoon(RetainPtr<T>&&); | |
6fe7ccc8 | 229 | #endif |
14957cd0 | 230 | |
81345200 A |
231 | void removeCodeBlock(CodeBlock* cb) { m_codeBlocks.remove(cb); } |
232 | ||
233 | static bool isZombified(JSCell* cell) { return *(void**)cell == zombifiedBits; } | |
234 | ||
ed1e77d3 A |
235 | void registerWeakGCMap(void* weakGCMap, std::function<void()> pruningCallback); |
236 | void unregisterWeakGCMap(void* weakGCMap); | |
237 | ||
238 | void addLogicallyEmptyWeakBlock(WeakBlock*); | |
239 | ||
81345200 A |
240 | private: |
241 | friend class CodeBlock; | |
242 | friend class CopiedBlock; | |
243 | friend class DeferGC; | |
244 | friend class DeferGCForAWhile; | |
81345200 A |
245 | friend class GCAwareJITStubRoutine; |
246 | friend class GCLogging; | |
247 | friend class HandleSet; | |
ed1e77d3 | 248 | friend class HeapVerifier; |
81345200 A |
249 | friend class JITStubRoutine; |
250 | friend class LLIntOffsetsExtractor; | |
251 | friend class MarkedSpace; | |
252 | friend class MarkedAllocator; | |
253 | friend class MarkedBlock; | |
254 | friend class CopiedSpace; | |
255 | friend class CopyVisitor; | |
256 | friend class RecursiveAllocationScope; | |
257 | friend class SlotVisitor; | |
258 | friend class SuperRegion; | |
259 | friend class IncrementalSweeper; | |
260 | friend class HeapStatistics; | |
261 | friend class VM; | |
262 | friend class WeakSet; | |
263 | template<typename T> friend void* allocateCell(Heap&); | |
264 | template<typename T> friend void* allocateCell(Heap&, size_t); | |
265 | ||
ed1e77d3 | 266 | void* allocateWithDestructor(size_t); // For use with objects with destructors. |
81345200 | 267 | void* allocateWithoutDestructor(size_t); // For use with objects without destructors. |
ed1e77d3 | 268 | template<typename ClassType> void* allocateObjectOfType(size_t); // Chooses one of the methods above based on type. |
81345200 | 269 | |
ed1e77d3 | 270 | static const size_t minExtraMemory = 256; |
81345200 A |
271 | |
272 | class FinalizerOwner : public WeakHandleOwner { | |
273 | virtual void finalize(Handle<Unknown>, void* context) override; | |
93a37866 A |
274 | }; |
275 | ||
81345200 | 276 | JS_EXPORT_PRIVATE bool isValidAllocation(size_t); |
ed1e77d3 A |
277 | JS_EXPORT_PRIVATE void reportExtraMemoryAllocatedSlowCase(size_t); |
278 | JS_EXPORT_PRIVATE void deprecatedReportExtraMemorySlowCase(size_t); | |
279 | ||
280 | void collectImpl(HeapOperation, void* stackOrigin, void* stackTop, MachineThreads::RegisterState&); | |
81345200 A |
281 | |
282 | void suspendCompilerThreads(); | |
283 | void willStartCollection(HeapOperation collectionType); | |
284 | void deleteOldCode(double gcStartTime); | |
285 | void flushOldStructureIDTables(); | |
286 | void flushWriteBarrierBuffer(); | |
287 | void stopAllocation(); | |
288 | ||
ed1e77d3 A |
289 | void markRoots(double gcStartTime, void* stackOrigin, void* stackTop, MachineThreads::RegisterState&); |
290 | void gatherStackRoots(ConservativeRoots&, void* stackOrigin, void* stackTop, MachineThreads::RegisterState&); | |
81345200 A |
291 | void gatherJSStackRoots(ConservativeRoots&); |
292 | void gatherScratchBufferRoots(ConservativeRoots&); | |
293 | void clearLivenessData(); | |
294 | void visitExternalRememberedSet(); | |
295 | void visitSmallStrings(); | |
296 | void visitConservativeRoots(ConservativeRoots&); | |
297 | void visitCompilerWorklistWeakReferences(); | |
298 | void removeDeadCompilerWorklistEntries(); | |
299 | void visitProtectedObjects(HeapRootVisitor&); | |
81345200 A |
300 | void visitArgumentBuffers(HeapRootVisitor&); |
301 | void visitException(HeapRootVisitor&); | |
302 | void visitStrongHandles(HeapRootVisitor&); | |
303 | void visitHandleStack(HeapRootVisitor&); | |
304 | void traceCodeBlocksAndJITStubRoutines(); | |
305 | void converge(); | |
306 | void visitWeakHandles(HeapRootVisitor&); | |
307 | void clearRememberedSet(Vector<const JSCell*>&); | |
308 | void updateObjectCounts(double gcStartTime); | |
309 | void resetVisitors(); | |
310 | ||
311 | void reapWeakHandles(); | |
ed1e77d3 | 312 | void pruneStaleEntriesFromWeakGCMaps(); |
81345200 A |
313 | void sweepArrayBuffers(); |
314 | void snapshotMarkedSpace(); | |
315 | void deleteSourceProviderCaches(); | |
316 | void notifyIncrementalSweeper(); | |
317 | void rememberCurrentlyExecutingCodeBlocks(); | |
318 | void resetAllocators(); | |
319 | void copyBackingStores(); | |
320 | void harvestWeakReferences(); | |
321 | void finalizeUnconditionalFinalizers(); | |
322 | void clearUnmarkedExecutables(); | |
323 | void deleteUnmarkedCompiledCode(); | |
324 | void updateAllocationLimits(); | |
325 | void didFinishCollection(double gcStartTime); | |
326 | void resumeCompilerThreads(); | |
327 | void zombifyDeadObjects(); | |
328 | void markDeadObjects(); | |
329 | ||
ed1e77d3 A |
330 | void sweepAllLogicallyEmptyWeakBlocks(); |
331 | bool sweepNextLogicallyEmptyWeakBlock(); | |
332 | ||
81345200 A |
333 | bool shouldDoFullCollection(HeapOperation requestedCollectionType) const; |
334 | size_t sizeAfterCollect(); | |
335 | ||
336 | JSStack& stack(); | |
93a37866 | 337 | |
81345200 A |
338 | void incrementDeferralDepth(); |
339 | void decrementDeferralDepth(); | |
340 | void decrementDeferralDepthAndGCIfNeeded(); | |
341 | ||
342 | const HeapType m_heapType; | |
343 | const size_t m_ramSize; | |
344 | const size_t m_minBytesPerCycle; | |
345 | size_t m_sizeAfterLastCollect; | |
346 | size_t m_sizeAfterLastFullCollect; | |
347 | size_t m_sizeBeforeLastFullCollect; | |
348 | size_t m_sizeAfterLastEdenCollect; | |
349 | size_t m_sizeBeforeLastEdenCollect; | |
350 | ||
351 | size_t m_bytesAllocatedThisCycle; | |
352 | size_t m_bytesAbandonedSinceLastFullCollect; | |
353 | size_t m_maxEdenSize; | |
354 | size_t m_maxHeapSize; | |
355 | bool m_shouldDoFullCollection; | |
356 | size_t m_totalBytesVisited; | |
357 | size_t m_totalBytesCopied; | |
93a37866 | 358 | |
81345200 | 359 | HeapOperation m_operationInProgress; |
81345200 A |
360 | StructureIDTable m_structureIDTable; |
361 | MarkedSpace m_objectSpace; | |
362 | CopiedSpace m_storageSpace; | |
363 | GCIncomingRefCountedSet<ArrayBuffer> m_arrayBuffers; | |
ed1e77d3 A |
364 | size_t m_extraMemorySize; |
365 | size_t m_deprecatedExtraMemorySize; | |
14957cd0 | 366 | |
81345200 A |
367 | HashSet<const JSCell*> m_copyingRememberedSet; |
368 | ||
369 | ProtectCountSet m_protectedValues; | |
ed1e77d3 | 370 | std::unique_ptr<HashSet<MarkedArgumentBuffer*>> m_markListSet; |
81345200 A |
371 | |
372 | MachineThreads m_machineThreads; | |
373 | ||
374 | GCThreadSharedData m_sharedData; | |
375 | SlotVisitor m_slotVisitor; | |
376 | CopyVisitor m_copyVisitor; | |
377 | ||
378 | HandleSet m_handleSet; | |
379 | HandleStack m_handleStack; | |
380 | CodeBlockSet m_codeBlocks; | |
381 | JITStubRoutineSet m_jitStubRoutines; | |
382 | FinalizerOwner m_finalizerOwner; | |
93a37866 | 383 | |
81345200 A |
384 | bool m_isSafeToCollect; |
385 | ||
386 | WriteBarrierBuffer m_writeBarrierBuffer; | |
387 | ||
388 | VM* m_vm; | |
389 | double m_lastFullGCLength; | |
390 | double m_lastEdenGCLength; | |
391 | double m_lastCodeDiscardTime; | |
392 | ||
ed1e77d3 A |
393 | Vector<ExecutableBase*> m_compiledCode; |
394 | ||
395 | Vector<WeakBlock*> m_logicallyEmptyWeakBlocks; | |
396 | size_t m_indexOfNextLogicallyEmptyWeakBlockToSweep { WTF::notFound }; | |
6fe7ccc8 | 397 | |
ed1e77d3 | 398 | RefPtr<FullGCActivityCallback> m_fullActivityCallback; |
81345200 | 399 | RefPtr<GCActivityCallback> m_edenActivityCallback; |
ed1e77d3 | 400 | std::unique_ptr<IncrementalSweeper> m_sweeper; |
81345200 | 401 | Vector<MarkedBlock*> m_blockSnapshot; |
6fe7ccc8 | 402 | |
81345200 A |
403 | unsigned m_deferralDepth; |
404 | Vector<DFG::Worklist*> m_suspendedCompilerWorklists; | |
ed1e77d3 A |
405 | |
406 | std::unique_ptr<HeapVerifier> m_verifier; | |
407 | #if USE(CF) | |
408 | Vector<RetainPtr<CFTypeRef>> m_delayedReleaseObjects; | |
409 | unsigned m_delayedReleaseRecursionCount; | |
410 | #endif | |
411 | ||
412 | HashMap<void*, std::function<void()>> m_weakGCMaps; | |
81345200 | 413 | }; |
14957cd0 A |
414 | |
415 | } // namespace JSC | |
416 | ||
417 | #endif // Heap_h |