DFG should be able to cache closure calls (part 2/2)
[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 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 JSGlobalData;
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(JSGlobalData*, HeapType);
100         ~Heap();
101         JS_EXPORT_PRIVATE void lastChanceToFinalize();
102
103         JSGlobalData* globalData() const { return m_globalData; }
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(GCActivityCallback*);
109         JS_EXPORT_PRIVATE void setGarbageCollectionTimerEnabled(bool);
110
111         JS_EXPORT_PRIVATE IncrementalSweeper* sweeper();
112
113         // true if an allocation or collection is in progress
114         inline bool isBusy();
115         
116         MarkedAllocator& firstAllocatorWithoutDestructors() { return m_objectSpace.firstAllocator(); }
117         MarkedAllocator& allocatorForObjectWithoutDestructor(size_t bytes) { return m_objectSpace.allocatorFor(bytes); }
118         MarkedAllocator& allocatorForObjectWithNormalDestructor(size_t bytes) { return m_objectSpace.normalDestructorAllocatorFor(bytes); }
119         MarkedAllocator& allocatorForObjectWithImmortalStructureDestructor(size_t bytes) { return m_objectSpace.immortalStructureDestructorAllocatorFor(bytes); }
120         CopiedAllocator& storageAllocator() { return m_storageSpace.allocator(); }
121         CheckedBoolean tryAllocateStorage(size_t, void**);
122         CheckedBoolean tryReallocateStorage(void**, size_t, size_t);
123
124         typedef void (*Finalizer)(JSCell*);
125         JS_EXPORT_PRIVATE void addFinalizer(JSCell*, Finalizer);
126         void addCompiledCode(ExecutableBase*);
127
128         void notifyIsSafeToCollect() { m_isSafeToCollect = true; }
129         bool isSafeToCollect() const { return m_isSafeToCollect; }
130
131         JS_EXPORT_PRIVATE void collectAllGarbage();
132         enum SweepToggle { DoNotSweep, DoSweep };
133         bool shouldCollect();
134         void collect(SweepToggle);
135
136         void reportExtraMemoryCost(size_t cost);
137         JS_EXPORT_PRIVATE void reportAbandonedObjectGraph();
138
139         JS_EXPORT_PRIVATE void protect(JSValue);
140         JS_EXPORT_PRIVATE bool unprotect(JSValue); // True when the protect count drops to 0.
141         
142         void jettisonDFGCodeBlock(PassOwnPtr<CodeBlock>);
143
144         JS_EXPORT_PRIVATE size_t size();
145         JS_EXPORT_PRIVATE size_t capacity();
146         JS_EXPORT_PRIVATE size_t objectCount();
147         JS_EXPORT_PRIVATE size_t globalObjectCount();
148         JS_EXPORT_PRIVATE size_t protectedObjectCount();
149         JS_EXPORT_PRIVATE size_t protectedGlobalObjectCount();
150         JS_EXPORT_PRIVATE PassOwnPtr<TypeCountSet> protectedObjectTypeCounts();
151         JS_EXPORT_PRIVATE PassOwnPtr<TypeCountSet> objectTypeCounts();
152         void showStatistics();
153
154         void pushTempSortVector(Vector<ValueStringPair>*);
155         void popTempSortVector(Vector<ValueStringPair>*);
156     
157         HashSet<MarkedArgumentBuffer*>& markListSet() { if (!m_markListSet) m_markListSet = adoptPtr(new HashSet<MarkedArgumentBuffer*>); return *m_markListSet; }
158         
159         template<typename Functor> typename Functor::ReturnType forEachProtectedCell(Functor&);
160         template<typename Functor> typename Functor::ReturnType forEachProtectedCell();
161
162         HandleSet* handleSet() { return &m_handleSet; }
163         HandleStack* handleStack() { return &m_handleStack; }
164
165         void getConservativeRegisterRoots(HashSet<JSCell*>& roots);
166
167         double lastGCLength() { return m_lastGCLength; }
168         void increaseLastGCLength(double amount) { m_lastGCLength += amount; }
169
170         JS_EXPORT_PRIVATE void deleteAllCompiledCode();
171
172         void didAllocate(size_t);
173         void didAbandon(size_t);
174
175         bool isPagedOut(double deadline);
176         void didStartVMShutdown();
177         
178         const JITStubRoutineSet& jitStubRoutines() { return m_jitStubRoutines; }
179
180     private:
181         friend class CodeBlock;
182         friend class GCAwareJITStubRoutine;
183         friend class JITStubRoutine;
184         friend class LLIntOffsetsExtractor;
185         friend class MarkedSpace;
186         friend class MarkedAllocator;
187         friend class MarkedBlock;
188         friend class CopiedSpace;
189         friend class CopyVisitor;
190         friend class SlotVisitor;
191         friend class IncrementalSweeper;
192         friend class HeapStatistics;
193         friend class WeakSet;
194         template<typename T> friend void* allocateCell(Heap&);
195         template<typename T> friend void* allocateCell(Heap&, size_t);
196
197         void* allocateWithImmortalStructureDestructor(size_t); // For use with special objects whose Structures never die.
198         void* allocateWithNormalDestructor(size_t); // For use with objects that inherit directly or indirectly from JSDestructibleObject.
199         void* allocateWithoutDestructor(size_t); // For use with objects without destructors.
200
201         static const size_t minExtraCost = 256;
202         static const size_t maxExtraCost = 1024 * 1024;
203         
204         class FinalizerOwner : public WeakHandleOwner {
205             virtual void finalize(Handle<Unknown>, void* context);
206         };
207
208         JS_EXPORT_PRIVATE bool isValidAllocation(size_t);
209         JS_EXPORT_PRIVATE void reportExtraMemoryCostSlowCase(size_t);
210
211         void markRoots(bool fullGC);
212         void markProtectedObjects(HeapRootVisitor&);
213         void markTempSortVectors(HeapRootVisitor&);
214         void copyBackingStores();
215         void harvestWeakReferences();
216         void finalizeUnconditionalFinalizers();
217         void deleteUnmarkedCompiledCode();
218         void zombifyDeadObjects();
219         void markDeadObjects();
220
221         JSStack& stack();
222         BlockAllocator& blockAllocator();
223
224         const HeapType m_heapType;
225         const size_t m_ramSize;
226         const size_t m_minBytesPerCycle;
227         size_t m_sizeAfterLastCollect;
228
229         size_t m_bytesAllocatedLimit;
230         size_t m_bytesAllocated;
231         size_t m_bytesAbandoned;
232         
233         OperationInProgress m_operationInProgress;
234         BlockAllocator m_blockAllocator;
235         MarkedSpace m_objectSpace;
236         CopiedSpace m_storageSpace;
237
238 #if ENABLE(SIMPLE_HEAP_PROFILING)
239         VTableSpectrum m_destroyedTypeCounts;
240 #endif
241
242         ProtectCountSet m_protectedValues;
243         Vector<Vector<ValueStringPair>* > m_tempSortingVectors;
244         OwnPtr<HashSet<MarkedArgumentBuffer*> > m_markListSet;
245
246         MachineThreads m_machineThreads;
247         
248         GCThreadSharedData m_sharedData;
249         SlotVisitor m_slotVisitor;
250         CopyVisitor m_copyVisitor;
251
252         HandleSet m_handleSet;
253         HandleStack m_handleStack;
254         DFGCodeBlocks m_dfgCodeBlocks;
255         JITStubRoutineSet m_jitStubRoutines;
256         FinalizerOwner m_finalizerOwner;
257         
258         bool m_isSafeToCollect;
259
260         JSGlobalData* m_globalData;
261         double m_lastGCLength;
262         double m_lastCodeDiscardTime;
263
264         DoublyLinkedList<ExecutableBase> m_compiledCode;
265         
266         GCActivityCallback* m_activityCallback;
267         IncrementalSweeper* m_sweeper;
268         Vector<MarkedBlock*> m_blockSnapshot;
269     };
270
271     struct MarkedBlockSnapshotFunctor : public MarkedBlock::VoidFunctor {
272         MarkedBlockSnapshotFunctor(Vector<MarkedBlock*>& blocks) 
273             : m_index(0) 
274             , m_blocks(blocks)
275         {
276         }
277     
278         void operator()(MarkedBlock* block) { m_blocks[m_index++] = block; }
279     
280         size_t m_index;
281         Vector<MarkedBlock*>& m_blocks;
282     };
283
284     inline bool Heap::shouldCollect()
285     {
286         if (Options::gcMaxHeapSize())
287             return m_bytesAllocated > Options::gcMaxHeapSize() && m_isSafeToCollect && m_operationInProgress == NoOperation;
288 #if ENABLE(GGC)
289         return m_objectSpace.nurseryWaterMark() >= m_minBytesPerCycle && m_isSafeToCollect && m_operationInProgress == NoOperation;
290 #else
291         return m_bytesAllocated > m_bytesAllocatedLimit && m_isSafeToCollect && m_operationInProgress == NoOperation;
292 #endif
293     }
294
295     bool Heap::isBusy()
296     {
297         return m_operationInProgress != NoOperation;
298     }
299
300     inline Heap* Heap::heap(const JSCell* cell)
301     {
302         return MarkedBlock::blockFor(cell)->heap();
303     }
304
305     inline Heap* Heap::heap(const JSValue v)
306     {
307         if (!v.isCell())
308             return 0;
309         return heap(v.asCell());
310     }
311
312     inline bool Heap::isLive(const void* cell)
313     {
314         return MarkedBlock::blockFor(cell)->isLiveCell(cell);
315     }
316
317     inline bool Heap::isMarked(const void* cell)
318     {
319         return MarkedBlock::blockFor(cell)->isMarked(cell);
320     }
321
322     inline bool Heap::testAndSetMarked(const void* cell)
323     {
324         return MarkedBlock::blockFor(cell)->testAndSetMarked(cell);
325     }
326
327     inline void Heap::setMarked(const void* cell)
328     {
329         MarkedBlock::blockFor(cell)->setMarked(cell);
330     }
331
332     inline bool Heap::isWriteBarrierEnabled()
333     {
334 #if ENABLE(GGC) || ENABLE(WRITE_BARRIER_PROFILING)
335         return true;
336 #else
337         return false;
338 #endif
339     }
340
341 #if ENABLE(GGC)
342     inline uint8_t* Heap::addressOfCardFor(JSCell* cell)
343     {
344         return MarkedBlock::blockFor(cell)->addressOfCardFor(cell);
345     }
346
347     inline void Heap::writeBarrier(const JSCell* owner, JSCell*)
348     {
349         WriteBarrierCounters::countWriteBarrier();
350         MarkedBlock* block = MarkedBlock::blockFor(owner);
351         if (block->isMarked(owner))
352             block->setDirtyObject(owner);
353     }
354
355     inline void Heap::writeBarrier(const JSCell* owner, JSValue value)
356     {
357         if (!value)
358             return;
359         if (!value.isCell())
360             return;
361         writeBarrier(owner, value.asCell());
362     }
363 #else
364
365     inline void Heap::writeBarrier(const JSCell*, JSCell*)
366     {
367         WriteBarrierCounters::countWriteBarrier();
368     }
369
370     inline void Heap::writeBarrier(const JSCell*, JSValue)
371     {
372         WriteBarrierCounters::countWriteBarrier();
373     }
374 #endif
375
376     inline void Heap::reportExtraMemoryCost(size_t cost)
377     {
378         if (cost > minExtraCost) 
379             reportExtraMemoryCostSlowCase(cost);
380     }
381
382     template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell(Functor& functor)
383     {
384         ProtectCountSet::iterator end = m_protectedValues.end();
385         for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it)
386             functor(it->key);
387         m_handleSet.forEachStrongHandle(functor, m_protectedValues);
388
389         return functor.returnValue();
390     }
391
392     template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell()
393     {
394         Functor functor;
395         return forEachProtectedCell(functor);
396     }
397
398     inline void* Heap::allocateWithNormalDestructor(size_t bytes)
399     {
400         ASSERT(isValidAllocation(bytes));
401         return m_objectSpace.allocateWithNormalDestructor(bytes);
402     }
403     
404     inline void* Heap::allocateWithImmortalStructureDestructor(size_t bytes)
405     {
406         ASSERT(isValidAllocation(bytes));
407         return m_objectSpace.allocateWithImmortalStructureDestructor(bytes);
408     }
409     
410     inline void* Heap::allocateWithoutDestructor(size_t bytes)
411     {
412         ASSERT(isValidAllocation(bytes));
413         return m_objectSpace.allocateWithoutDestructor(bytes);
414     }
415    
416     inline CheckedBoolean Heap::tryAllocateStorage(size_t bytes, void** outPtr)
417     {
418         return m_storageSpace.tryAllocate(bytes, outPtr);
419     }
420     
421     inline CheckedBoolean Heap::tryReallocateStorage(void** ptr, size_t oldSize, size_t newSize)
422     {
423         return m_storageSpace.tryReallocate(ptr, oldSize, newSize);
424     }
425
426     inline BlockAllocator& Heap::blockAllocator()
427     {
428         return m_blockAllocator;
429     }
430
431 } // namespace JSC
432
433 #endif // Heap_h