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