releaseExecutableMemory() should canonicalize cell liveness data before
[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(PassOwnPtr<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, 0, UnsafeVectorOverflow>*);
154         void popTempSortVector(Vector<ValueStringPair, 0, UnsafeVectorOverflow>*);
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 canonicalizeCellLivenessData();
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         
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 SuperRegion;
193         friend class IncrementalSweeper;
194         friend class HeapStatistics;
195         friend class WeakSet;
196         template<typename T> friend void* allocateCell(Heap&);
197         template<typename T> friend void* allocateCell(Heap&, size_t);
198
199         void* allocateWithImmortalStructureDestructor(size_t); // For use with special objects whose Structures never die.
200         void* allocateWithNormalDestructor(size_t); // For use with objects that inherit directly or indirectly from JSDestructibleObject.
201         void* allocateWithoutDestructor(size_t); // For use with objects without destructors.
202
203         static const size_t minExtraCost = 256;
204         static const size_t maxExtraCost = 1024 * 1024;
205         
206         class FinalizerOwner : public WeakHandleOwner {
207             virtual void finalize(Handle<Unknown>, void* context);
208         };
209
210         JS_EXPORT_PRIVATE bool isValidAllocation(size_t);
211         JS_EXPORT_PRIVATE void reportExtraMemoryCostSlowCase(size_t);
212
213         void markRoots();
214         void markProtectedObjects(HeapRootVisitor&);
215         void markTempSortVectors(HeapRootVisitor&);
216         void copyBackingStores();
217         void harvestWeakReferences();
218         void finalizeUnconditionalFinalizers();
219         void deleteUnmarkedCompiledCode();
220         void zombifyDeadObjects();
221         void markDeadObjects();
222
223         JSStack& stack();
224         BlockAllocator& blockAllocator();
225
226         const HeapType m_heapType;
227         const size_t m_ramSize;
228         const size_t m_minBytesPerCycle;
229         size_t m_sizeAfterLastCollect;
230
231         size_t m_bytesAllocatedLimit;
232         size_t m_bytesAllocated;
233         size_t m_bytesAbandoned;
234         
235         OperationInProgress m_operationInProgress;
236         BlockAllocator m_blockAllocator;
237         MarkedSpace m_objectSpace;
238         CopiedSpace m_storageSpace;
239
240 #if ENABLE(SIMPLE_HEAP_PROFILING)
241         VTableSpectrum m_destroyedTypeCounts;
242 #endif
243
244         ProtectCountSet m_protectedValues;
245         Vector<Vector<ValueStringPair, 0, UnsafeVectorOverflow>* > m_tempSortingVectors;
246         OwnPtr<HashSet<MarkedArgumentBuffer*> > m_markListSet;
247
248         MachineThreads m_machineThreads;
249         
250         GCThreadSharedData m_sharedData;
251         SlotVisitor m_slotVisitor;
252         CopyVisitor m_copyVisitor;
253
254         HandleSet m_handleSet;
255         HandleStack m_handleStack;
256         DFGCodeBlocks m_dfgCodeBlocks;
257         JITStubRoutineSet m_jitStubRoutines;
258         FinalizerOwner m_finalizerOwner;
259         
260         bool m_isSafeToCollect;
261
262         JSGlobalData* m_globalData;
263         double m_lastGCLength;
264         double m_lastCodeDiscardTime;
265
266         DoublyLinkedList<ExecutableBase> m_compiledCode;
267         
268         OwnPtr<GCActivityCallback> m_activityCallback;
269         OwnPtr<IncrementalSweeper> m_sweeper;
270         Vector<MarkedBlock*> m_blockSnapshot;
271     };
272
273     struct MarkedBlockSnapshotFunctor : public MarkedBlock::VoidFunctor {
274         MarkedBlockSnapshotFunctor(Vector<MarkedBlock*>& blocks) 
275             : m_index(0) 
276             , m_blocks(blocks)
277         {
278         }
279     
280         void operator()(MarkedBlock* block) { m_blocks[m_index++] = block; }
281     
282         size_t m_index;
283         Vector<MarkedBlock*>& m_blocks;
284     };
285
286     inline bool Heap::shouldCollect()
287     {
288         if (Options::gcMaxHeapSize())
289             return m_bytesAllocated > Options::gcMaxHeapSize() && m_isSafeToCollect && m_operationInProgress == NoOperation;
290         return m_bytesAllocated > m_bytesAllocatedLimit && m_isSafeToCollect && m_operationInProgress == NoOperation;
291     }
292
293     bool Heap::isBusy()
294     {
295         return m_operationInProgress != NoOperation;
296     }
297
298     inline Heap* Heap::heap(const JSCell* cell)
299     {
300         return MarkedBlock::blockFor(cell)->heap();
301     }
302
303     inline Heap* Heap::heap(const JSValue v)
304     {
305         if (!v.isCell())
306             return 0;
307         return heap(v.asCell());
308     }
309
310     inline bool Heap::isLive(const void* cell)
311     {
312         return MarkedBlock::blockFor(cell)->isLiveCell(cell);
313     }
314
315     inline bool Heap::isMarked(const void* cell)
316     {
317         return MarkedBlock::blockFor(cell)->isMarked(cell);
318     }
319
320     inline bool Heap::testAndSetMarked(const void* cell)
321     {
322         return MarkedBlock::blockFor(cell)->testAndSetMarked(cell);
323     }
324
325     inline void Heap::setMarked(const void* cell)
326     {
327         MarkedBlock::blockFor(cell)->setMarked(cell);
328     }
329
330     inline bool Heap::isWriteBarrierEnabled()
331     {
332 #if ENABLE(WRITE_BARRIER_PROFILING)
333         return true;
334 #else
335         return false;
336 #endif
337     }
338
339     inline void Heap::writeBarrier(const JSCell*, JSCell*)
340     {
341         WriteBarrierCounters::countWriteBarrier();
342     }
343
344     inline void Heap::writeBarrier(const JSCell*, JSValue)
345     {
346         WriteBarrierCounters::countWriteBarrier();
347     }
348
349     inline void Heap::reportExtraMemoryCost(size_t cost)
350     {
351         if (cost > minExtraCost) 
352             reportExtraMemoryCostSlowCase(cost);
353     }
354
355     template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell(Functor& functor)
356     {
357         ProtectCountSet::iterator end = m_protectedValues.end();
358         for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it)
359             functor(it->key);
360         m_handleSet.forEachStrongHandle(functor, m_protectedValues);
361
362         return functor.returnValue();
363     }
364
365     template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell()
366     {
367         Functor functor;
368         return forEachProtectedCell(functor);
369     }
370
371     inline void* Heap::allocateWithNormalDestructor(size_t bytes)
372     {
373         ASSERT(isValidAllocation(bytes));
374         return m_objectSpace.allocateWithNormalDestructor(bytes);
375     }
376     
377     inline void* Heap::allocateWithImmortalStructureDestructor(size_t bytes)
378     {
379         ASSERT(isValidAllocation(bytes));
380         return m_objectSpace.allocateWithImmortalStructureDestructor(bytes);
381     }
382     
383     inline void* Heap::allocateWithoutDestructor(size_t bytes)
384     {
385         ASSERT(isValidAllocation(bytes));
386         return m_objectSpace.allocateWithoutDestructor(bytes);
387     }
388    
389     inline CheckedBoolean Heap::tryAllocateStorage(size_t bytes, void** outPtr)
390     {
391         return m_storageSpace.tryAllocate(bytes, outPtr);
392     }
393     
394     inline CheckedBoolean Heap::tryReallocateStorage(void** ptr, size_t oldSize, size_t newSize)
395     {
396         return m_storageSpace.tryReallocate(ptr, oldSize, newSize);
397     }
398
399     inline BlockAllocator& Heap::blockAllocator()
400     {
401         return m_blockAllocator;
402     }
403
404 } // namespace JSC
405
406 #endif // Heap_h