5d4ef76e4685a169a7c039f2f511aaa7d6647827
[WebKit-https.git] / Source / JavaScriptCore / heap / Heap.h
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, 2013 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
25 #include "BlockAllocator.h"
26 #include "CopyVisitor.h"
27 #include "DFGCodeBlocks.h"
28 #include "GCThreadSharedData.h"
29 #include "HandleSet.h"
30 #include "HandleStack.h"
31 #include "JITStubRoutineSet.h"
32 #include "MarkedAllocator.h"
33 #include "MarkedBlock.h"
34 #include "MarkedBlockSet.h"
35 #include "MarkedSpace.h"
36 #include "Options.h"
37 #include "SlotVisitor.h"
38 #include "WeakHandleOwner.h"
39 #include "WriteBarrierSupport.h"
40 #include <wtf/HashCountedSet.h>
41 #include <wtf/HashSet.h>
42
43 #define COLLECT_ON_EVERY_ALLOCATION 0
44
45 namespace JSC {
46
47     class CopiedSpace;
48     class CodeBlock;
49     class ExecutableBase;
50     class GCActivityCallback;
51     class GCAwareJITStubRoutine;
52     class GlobalCodeBlock;
53     class Heap;
54     class HeapRootVisitor;
55     class IncrementalSweeper;
56     class JITStubRoutine;
57     class JSCell;
58     class VM;
59     class JSStack;
60     class JSValue;
61     class LiveObjectIterator;
62     class LLIntOffsetsExtractor;
63     class MarkedArgumentBuffer;
64     class WeakGCHandlePool;
65     class SlotVisitor;
66
67     typedef std::pair<JSValue, WTF::String> ValueStringPair;
68     typedef HashCountedSet<JSCell*> ProtectCountSet;
69     typedef HashCountedSet<const char*> TypeCountSet;
70
71     enum OperationInProgress { NoOperation, Allocation, Collection };
72
73     enum HeapType { SmallHeap, LargeHeap };
74
75     class Heap {
76         WTF_MAKE_NONCOPYABLE(Heap);
77     public:
78         friend class JIT;
79         friend class GCThreadSharedData;
80         static Heap* heap(const JSValue); // 0 for immediate values
81         static Heap* heap(const JSCell*);
82
83         // This constant determines how many blocks we iterate between checks of our 
84         // deadline when calling Heap::isPagedOut. Decreasing it will cause us to detect 
85         // overstepping our deadline more quickly, while increasing it will cause 
86         // our scan to run faster. 
87         static const unsigned s_timeCheckResolution = 16;
88
89         static bool isLive(const void*);
90         static bool isMarked(const void*);
91         static bool testAndSetMarked(const void*);
92         static void setMarked(const void*);
93
94         static bool isWriteBarrierEnabled();
95         static void writeBarrier(const JSCell*, JSValue);
96         static void writeBarrier(const JSCell*, JSCell*);
97         static uint8_t* addressOfCardFor(JSCell*);
98
99         Heap(VM*, HeapType);
100         ~Heap();
101         JS_EXPORT_PRIVATE void lastChanceToFinalize();
102
103         VM* vm() const { return m_vm; }
104         MarkedSpace& objectSpace() { return m_objectSpace; }
105         MachineThreads& machineThreads() { return m_machineThreads; }
106
107         JS_EXPORT_PRIVATE GCActivityCallback* activityCallback();
108         JS_EXPORT_PRIVATE void setActivityCallback(PassOwnPtr<GCActivityCallback>);
109         JS_EXPORT_PRIVATE void setGarbageCollectionTimerEnabled(bool);
110
111         JS_EXPORT_PRIVATE IncrementalSweeper* sweeper();
112
113         // true if collection is in progress
114         inline bool isCollecting();
115         // true if an allocation or collection is in progress
116         inline bool isBusy();
117         
118         MarkedAllocator& allocatorForObjectWithoutDestructor(size_t bytes) { return m_objectSpace.allocatorFor(bytes); }
119         MarkedAllocator& allocatorForObjectWithNormalDestructor(size_t bytes) { return m_objectSpace.normalDestructorAllocatorFor(bytes); }
120         MarkedAllocator& allocatorForObjectWithImmortalStructureDestructor(size_t bytes) { return m_objectSpace.immortalStructureDestructorAllocatorFor(bytes); }
121         CopiedAllocator& storageAllocator() { return m_storageSpace.allocator(); }
122         CheckedBoolean tryAllocateStorage(JSCell* intendedOwner, size_t, void**);
123         CheckedBoolean tryReallocateStorage(JSCell* intendedOwner, void**, size_t, size_t);
124         void ascribeOwner(JSCell* intendedOwner, void*);
125
126         typedef void (*Finalizer)(JSCell*);
127         JS_EXPORT_PRIVATE void addFinalizer(JSCell*, Finalizer);
128         void addCompiledCode(ExecutableBase*);
129
130         void notifyIsSafeToCollect() { m_isSafeToCollect = true; }
131         bool isSafeToCollect() const { return m_isSafeToCollect; }
132
133         JS_EXPORT_PRIVATE void collectAllGarbage();
134         enum SweepToggle { DoNotSweep, DoSweep };
135         bool shouldCollect();
136         void collect(SweepToggle);
137         bool collectIfNecessaryOrDefer(); // Returns true if it did collect.
138
139         void reportExtraMemoryCost(size_t cost);
140         JS_EXPORT_PRIVATE void reportAbandonedObjectGraph();
141
142         JS_EXPORT_PRIVATE void protect(JSValue);
143         JS_EXPORT_PRIVATE bool unprotect(JSValue); // True when the protect count drops to 0.
144         
145         void jettisonDFGCodeBlock(PassRefPtr<CodeBlock>);
146
147         JS_EXPORT_PRIVATE size_t size();
148         JS_EXPORT_PRIVATE size_t capacity();
149         JS_EXPORT_PRIVATE size_t objectCount();
150         JS_EXPORT_PRIVATE size_t globalObjectCount();
151         JS_EXPORT_PRIVATE size_t protectedObjectCount();
152         JS_EXPORT_PRIVATE size_t protectedGlobalObjectCount();
153         JS_EXPORT_PRIVATE PassOwnPtr<TypeCountSet> protectedObjectTypeCounts();
154         JS_EXPORT_PRIVATE PassOwnPtr<TypeCountSet> objectTypeCounts();
155         void showStatistics();
156
157         void pushTempSortVector(Vector<ValueStringPair, 0, UnsafeVectorOverflow>*);
158         void popTempSortVector(Vector<ValueStringPair, 0, UnsafeVectorOverflow>*);
159     
160         HashSet<MarkedArgumentBuffer*>& markListSet() { if (!m_markListSet) m_markListSet = adoptPtr(new HashSet<MarkedArgumentBuffer*>); return *m_markListSet; }
161         
162         template<typename Functor> typename Functor::ReturnType forEachProtectedCell(Functor&);
163         template<typename Functor> typename Functor::ReturnType forEachProtectedCell();
164
165         HandleSet* handleSet() { return &m_handleSet; }
166         HandleStack* handleStack() { return &m_handleStack; }
167
168         void canonicalizeCellLivenessData();
169         void getConservativeRegisterRoots(HashSet<JSCell*>& roots);
170
171         double lastGCLength() { return m_lastGCLength; }
172         void increaseLastGCLength(double amount) { m_lastGCLength += amount; }
173
174         JS_EXPORT_PRIVATE void deleteAllCompiledCode();
175
176         void didAllocate(size_t);
177         void didAbandon(size_t);
178
179         bool isPagedOut(double deadline);
180         
181         const JITStubRoutineSet& jitStubRoutines() { return m_jitStubRoutines; }
182
183     private:
184         friend class CodeBlock;
185         friend class CopiedBlock;
186         friend class DeferGC;
187         friend class GCAwareJITStubRoutine;
188         friend class HandleSet;
189         friend class JITStubRoutine;
190         friend class LLIntOffsetsExtractor;
191         friend class MarkedSpace;
192         friend class MarkedAllocator;
193         friend class MarkedBlock;
194         friend class CopiedSpace;
195         friend class CopyVisitor;
196         friend class SlotVisitor;
197         friend class SuperRegion;
198         friend class IncrementalSweeper;
199         friend class HeapStatistics;
200         friend class VM;
201         friend class WeakSet;
202         template<typename T> friend void* allocateCell(Heap&);
203         template<typename T> friend void* allocateCell(Heap&, size_t);
204
205         void* allocateWithImmortalStructureDestructor(size_t); // For use with special objects whose Structures never die.
206         void* allocateWithNormalDestructor(size_t); // For use with objects that inherit directly or indirectly from JSDestructibleObject.
207         void* allocateWithoutDestructor(size_t); // For use with objects without destructors.
208
209         static const size_t minExtraCost = 256;
210         static const size_t maxExtraCost = 1024 * 1024;
211         
212         class FinalizerOwner : public WeakHandleOwner {
213             virtual void finalize(Handle<Unknown>, void* context);
214         };
215
216         JS_EXPORT_PRIVATE bool isValidAllocation(size_t);
217         JS_EXPORT_PRIVATE void reportExtraMemoryCostSlowCase(size_t);
218
219         void markRoots();
220         void markProtectedObjects(HeapRootVisitor&);
221         void markTempSortVectors(HeapRootVisitor&);
222         void copyBackingStores();
223         void harvestWeakReferences();
224         void finalizeUnconditionalFinalizers();
225         void deleteUnmarkedCompiledCode();
226         void zombifyDeadObjects();
227         void markDeadObjects();
228
229         JSStack& stack();
230         BlockAllocator& blockAllocator();
231         
232         void incrementDeferralDepth();
233         void decrementDeferralDepthAndGCIfNeeded();
234
235         const HeapType m_heapType;
236         const size_t m_ramSize;
237         const size_t m_minBytesPerCycle;
238         size_t m_sizeAfterLastCollect;
239
240         size_t m_bytesAllocatedLimit;
241         size_t m_bytesAllocated;
242         size_t m_bytesAbandoned;
243         
244         OperationInProgress m_operationInProgress;
245         BlockAllocator m_blockAllocator;
246         MarkedSpace m_objectSpace;
247         CopiedSpace m_storageSpace;
248         size_t m_extraMemoryUsage;
249
250 #if ENABLE(SIMPLE_HEAP_PROFILING)
251         VTableSpectrum m_destroyedTypeCounts;
252 #endif
253
254         ProtectCountSet m_protectedValues;
255         Vector<Vector<ValueStringPair, 0, UnsafeVectorOverflow>* > m_tempSortingVectors;
256         OwnPtr<HashSet<MarkedArgumentBuffer*> > m_markListSet;
257
258         MachineThreads m_machineThreads;
259         
260         GCThreadSharedData m_sharedData;
261         SlotVisitor m_slotVisitor;
262         CopyVisitor m_copyVisitor;
263
264         HandleSet m_handleSet;
265         HandleStack m_handleStack;
266         DFGCodeBlocks m_dfgCodeBlocks;
267         JITStubRoutineSet m_jitStubRoutines;
268         FinalizerOwner m_finalizerOwner;
269         
270         bool m_isSafeToCollect;
271
272         VM* m_vm;
273         double m_lastGCLength;
274         double m_lastCodeDiscardTime;
275
276         DoublyLinkedList<ExecutableBase> m_compiledCode;
277         
278         OwnPtr<GCActivityCallback> m_activityCallback;
279         OwnPtr<IncrementalSweeper> m_sweeper;
280         Vector<MarkedBlock*> m_blockSnapshot;
281         
282         unsigned m_deferralDepth;
283     };
284
285     struct MarkedBlockSnapshotFunctor : public MarkedBlock::VoidFunctor {
286         MarkedBlockSnapshotFunctor(Vector<MarkedBlock*>& blocks) 
287             : m_index(0) 
288             , m_blocks(blocks)
289         {
290         }
291     
292         void operator()(MarkedBlock* block) { m_blocks[m_index++] = block; }
293     
294         size_t m_index;
295         Vector<MarkedBlock*>& m_blocks;
296     };
297
298     inline bool Heap::shouldCollect()
299     {
300         if (Options::gcMaxHeapSize())
301             return m_bytesAllocated > Options::gcMaxHeapSize() && m_isSafeToCollect && m_operationInProgress == NoOperation;
302         return m_bytesAllocated > m_bytesAllocatedLimit && m_isSafeToCollect && m_operationInProgress == NoOperation;
303     }
304
305     bool Heap::isBusy()
306     {
307         return m_operationInProgress != NoOperation;
308     }
309
310     bool Heap::isCollecting()
311     {
312         return m_operationInProgress == Collection;
313     }
314
315     inline Heap* Heap::heap(const JSCell* cell)
316     {
317         return MarkedBlock::blockFor(cell)->heap();
318     }
319
320     inline Heap* Heap::heap(const JSValue v)
321     {
322         if (!v.isCell())
323             return 0;
324         return heap(v.asCell());
325     }
326
327     inline bool Heap::isLive(const void* cell)
328     {
329         return MarkedBlock::blockFor(cell)->isLiveCell(cell);
330     }
331
332     inline bool Heap::isMarked(const void* cell)
333     {
334         return MarkedBlock::blockFor(cell)->isMarked(cell);
335     }
336
337     inline bool Heap::testAndSetMarked(const void* cell)
338     {
339         return MarkedBlock::blockFor(cell)->testAndSetMarked(cell);
340     }
341
342     inline void Heap::setMarked(const void* cell)
343     {
344         MarkedBlock::blockFor(cell)->setMarked(cell);
345     }
346
347     inline bool Heap::isWriteBarrierEnabled()
348     {
349 #if ENABLE(WRITE_BARRIER_PROFILING)
350         return true;
351 #else
352         return false;
353 #endif
354     }
355
356     inline void Heap::writeBarrier(const JSCell*, JSCell*)
357     {
358         WriteBarrierCounters::countWriteBarrier();
359     }
360
361     inline void Heap::writeBarrier(const JSCell*, JSValue)
362     {
363         WriteBarrierCounters::countWriteBarrier();
364     }
365
366     inline void Heap::reportExtraMemoryCost(size_t cost)
367     {
368         if (cost > minExtraCost) 
369             reportExtraMemoryCostSlowCase(cost);
370     }
371
372     template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell(Functor& functor)
373     {
374         ProtectCountSet::iterator end = m_protectedValues.end();
375         for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it)
376             functor(it->key);
377         m_handleSet.forEachStrongHandle(functor, m_protectedValues);
378
379         return functor.returnValue();
380     }
381
382     template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell()
383     {
384         Functor functor;
385         return forEachProtectedCell(functor);
386     }
387
388     inline void* Heap::allocateWithNormalDestructor(size_t bytes)
389     {
390 #if ENABLE(ALLOCATION_LOGGING)
391         dataLogF("JSC GC allocating %lu bytes with normal destructor.\n", bytes);
392 #endif
393         ASSERT(isValidAllocation(bytes));
394         return m_objectSpace.allocateWithNormalDestructor(bytes);
395     }
396     
397     inline void* Heap::allocateWithImmortalStructureDestructor(size_t bytes)
398     {
399 #if ENABLE(ALLOCATION_LOGGING)
400         dataLogF("JSC GC allocating %lu bytes with immortal structure destructor.\n", bytes);
401 #endif
402         ASSERT(isValidAllocation(bytes));
403         return m_objectSpace.allocateWithImmortalStructureDestructor(bytes);
404     }
405     
406     inline void* Heap::allocateWithoutDestructor(size_t bytes)
407     {
408 #if ENABLE(ALLOCATION_LOGGING)
409         dataLogF("JSC GC allocating %lu bytes without destructor.\n", bytes);
410 #endif
411         ASSERT(isValidAllocation(bytes));
412         return m_objectSpace.allocateWithoutDestructor(bytes);
413     }
414    
415     inline CheckedBoolean Heap::tryAllocateStorage(JSCell* intendedOwner, size_t bytes, void** outPtr)
416     {
417         CheckedBoolean result = m_storageSpace.tryAllocate(bytes, outPtr);
418 #if ENABLE(ALLOCATION_LOGGING)
419         dataLogF("JSC GC allocating %lu bytes of storage for %p: %p.\n", bytes, intendedOwner, *outPtr);
420 #else
421         UNUSED_PARAM(intendedOwner);
422 #endif
423         return result;
424     }
425     
426     inline CheckedBoolean Heap::tryReallocateStorage(JSCell* intendedOwner, void** ptr, size_t oldSize, size_t newSize)
427     {
428 #if ENABLE(ALLOCATION_LOGGING)
429         void* oldPtr = *ptr;
430 #endif
431         CheckedBoolean result = m_storageSpace.tryReallocate(ptr, oldSize, newSize);
432 #if ENABLE(ALLOCATION_LOGGING)
433         dataLogF("JSC GC reallocating %lu -> %lu bytes of storage for %p: %p -> %p.\n", oldSize, newSize, intendedOwner, oldPtr, *ptr);
434 #else
435         UNUSED_PARAM(intendedOwner);
436 #endif
437         return result;
438     }
439
440     inline void Heap::ascribeOwner(JSCell* intendedOwner, void* storage)
441     {
442 #if ENABLE(ALLOCATION_LOGGING)
443         dataLogF("JSC GC ascribing %p as owner of storage %p.\n", intendedOwner, storage);
444 #else
445         UNUSED_PARAM(intendedOwner);
446         UNUSED_PARAM(storage);
447 #endif
448     }
449
450     inline BlockAllocator& Heap::blockAllocator()
451     {
452         return m_blockAllocator;
453     }
454
455 } // namespace JSC
456
457 #endif // Heap_h