961c184aba2648c16e2b45f6709da57407cff04e
[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 "HandleHeap.h"
26 #include "HandleStack.h"
27 #include "MarkedBlock.h"
28 #include "MarkedBlockSet.h"
29 #include "NewSpace.h"
30 #include "SlotVisitor.h"
31 #include "WriteBarrierSupport.h"
32 #include <wtf/Forward.h>
33 #include <wtf/HashCountedSet.h>
34 #include <wtf/HashSet.h>
35
36 namespace JSC {
37
38     class GCActivityCallback;
39     class GlobalCodeBlock;
40     class HeapRootVisitor;
41     class JSCell;
42     class JSGlobalData;
43     class JSValue;
44     class LiveObjectIterator;
45     class MarkedArgumentBuffer;
46     class RegisterFile;
47     class UString;
48     class WeakGCHandlePool;
49     class SlotVisitor;
50
51     typedef std::pair<JSValue, UString> ValueStringPair;
52     typedef HashCountedSet<JSCell*> ProtectCountSet;
53     typedef HashCountedSet<const char*> TypeCountSet;
54
55     enum OperationInProgress { NoOperation, Allocation, Collection };
56     
57     // Heap size hint.
58     enum HeapSize { SmallHeap, LargeHeap };
59     
60     class Heap {
61         WTF_MAKE_NONCOPYABLE(Heap);
62     public:
63         static Heap* heap(JSValue); // 0 for immediate values
64         static Heap* heap(JSCell*);
65
66         static bool isMarked(const void*);
67         static bool testAndSetMarked(const void*);
68         static bool testAndClearMarked(const void*);
69         static void setMarked(const void*);
70
71         static void writeBarrier(const JSCell*, JSValue);
72         static void writeBarrier(const JSCell*, JSCell*);
73
74         Heap(JSGlobalData*, HeapSize);
75         ~Heap();
76         void destroy(); // JSGlobalData must call destroy() before ~Heap().
77
78         JSGlobalData* globalData() const { return m_globalData; }
79         NewSpace& markedSpace() { return m_newSpace; }
80         MachineThreads& machineThreads() { return m_machineThreads; }
81
82         GCActivityCallback* activityCallback();
83         void setActivityCallback(PassOwnPtr<GCActivityCallback>);
84
85         // true if an allocation or collection is in progress
86         inline bool isBusy();
87
88         void* allocate(size_t);
89         NewSpace::SizeClass& sizeClassFor(size_t);
90         void* allocate(NewSpace::SizeClass&);
91         void notifyIsSafeToCollect() { m_isSafeToCollect = true; }
92         void collectAllGarbage();
93
94         inline void* allocatePropertyStorage(size_t);
95         inline bool inPropertyStorageNursery(void*);
96
97         void reportExtraMemoryCost(size_t cost);
98
99         void protect(JSValue);
100         bool unprotect(JSValue); // True when the protect count drops to 0.
101
102         size_t size();
103         size_t capacity();
104         size_t objectCount();
105         size_t globalObjectCount();
106         size_t protectedObjectCount();
107         size_t protectedGlobalObjectCount();
108         PassOwnPtr<TypeCountSet> protectedObjectTypeCounts();
109         PassOwnPtr<TypeCountSet> objectTypeCounts();
110
111         void pushTempSortVector(Vector<ValueStringPair>*);
112         void popTempSortVector(Vector<ValueStringPair>*);
113     
114         HashSet<MarkedArgumentBuffer*>& markListSet() { if (!m_markListSet) m_markListSet = new HashSet<MarkedArgumentBuffer*>; return *m_markListSet; }
115         
116         template<typename Functor> typename Functor::ReturnType forEachProtectedCell(Functor&);
117         template<typename Functor> typename Functor::ReturnType forEachProtectedCell();
118         template<typename Functor> typename Functor::ReturnType forEachCell(Functor&);
119         template<typename Functor> typename Functor::ReturnType forEachCell();
120         template<typename Functor> typename Functor::ReturnType forEachBlock(Functor&);
121         template<typename Functor> typename Functor::ReturnType forEachBlock();
122         
123         HandleSlot allocateGlobalHandle() { return m_handleHeap.allocate(); }
124         HandleSlot allocateLocalHandle() { return m_handleStack.push(); }
125
126         HandleStack* handleStack() { return &m_handleStack; }
127         void getConservativeRegisterRoots(HashSet<JSCell*>& roots);
128
129     private:
130         friend class MarkedBlock;
131         
132         typedef HashSet<MarkedBlock*>::iterator BlockIterator;
133
134         static const size_t minExtraCost = 256;
135         static const size_t maxExtraCost = 1024 * 1024;
136         
137         enum AllocationEffort { AllocationMustSucceed, AllocationCanFail };
138         
139 #if ENABLE(GGC)
140         static void writeBarrierFastCase(const JSCell* owner, JSCell*);
141 #endif
142
143         bool isValidAllocation(size_t);
144         void reportExtraMemoryCostSlowCase(size_t);
145         void canonicalizeBlocks();
146         void resetAllocator();
147
148         MarkedBlock* allocateBlock(size_t cellSize, AllocationEffort);
149         void freeBlocks(MarkedBlock*);
150
151         void clearMarks();
152         void markRoots();
153         void markProtectedObjects(HeapRootVisitor&);
154         void markTempSortVectors(HeapRootVisitor&);
155         void harvestWeakReferences();
156
157         void* tryAllocate(NewSpace::SizeClass&);
158         void* allocateSlowCase(NewSpace::SizeClass&);
159         
160         enum SweepToggle { DoNotSweep, DoSweep };
161         void collect(SweepToggle);
162         void shrink();
163         void releaseFreeBlocks();
164         void sweep();
165
166         RegisterFile& registerFile();
167
168         static void writeBarrierSlowCase(const JSCell*, JSCell*);
169         
170 #if ENABLE(LAZY_BLOCK_FREEING)
171         void waitForRelativeTimeWhileHoldingLock(double relative);
172         void waitForRelativeTime(double relative);
173         void blockFreeingThreadMain();
174         static void* blockFreeingThreadStartFunc(void* heap);
175 #endif
176
177         const HeapSize m_heapSize;
178         const size_t m_minBytesPerCycle;
179         
180         OperationInProgress m_operationInProgress;
181         NewSpace m_newSpace;
182         MarkedBlockSet m_blocks;
183
184 #if ENABLE(LAZY_BLOCK_FREEING)
185         DoublyLinkedList<MarkedBlock> m_freeBlocks;
186         size_t m_numberOfFreeBlocks;
187         
188         ThreadIdentifier m_blockFreeingThread;
189         Mutex m_freeBlockLock;
190         ThreadCondition m_freeBlockCondition;
191         bool m_blockFreeingThreadShouldQuit;
192 #endif
193
194 #if ENABLE(SIMPLE_HEAP_PROFILING)
195         VTableSpectrum m_destroyedTypeCounts;
196 #endif
197
198         size_t m_extraCost;
199
200         ProtectCountSet m_protectedValues;
201         Vector<Vector<ValueStringPair>* > m_tempSortingVectors;
202         HashSet<MarkedArgumentBuffer*>* m_markListSet;
203
204         OwnPtr<GCActivityCallback> m_activityCallback;
205         
206         MachineThreads m_machineThreads;
207         SlotVisitor m_slotVisitor;
208         HandleHeap m_handleHeap;
209         HandleStack m_handleStack;
210         
211         bool m_isSafeToCollect;
212
213         JSGlobalData* m_globalData;
214     };
215
216     bool Heap::isBusy()
217     {
218         return m_operationInProgress != NoOperation;
219     }
220
221     inline Heap* Heap::heap(JSCell* cell)
222     {
223         return MarkedBlock::blockFor(cell)->heap();
224     }
225
226     inline Heap* Heap::heap(JSValue v)
227     {
228         if (!v.isCell())
229             return 0;
230         return heap(v.asCell());
231     }
232
233     inline bool Heap::isMarked(const void* cell)
234     {
235         return MarkedBlock::blockFor(cell)->isMarked(cell);
236     }
237
238     inline bool Heap::testAndSetMarked(const void* cell)
239     {
240         return MarkedBlock::blockFor(cell)->testAndSetMarked(cell);
241     }
242
243     inline bool Heap::testAndClearMarked(const void* cell)
244     {
245         return MarkedBlock::blockFor(cell)->testAndClearMarked(cell);
246     }
247
248     inline void Heap::setMarked(const void* cell)
249     {
250         MarkedBlock::blockFor(cell)->setMarked(cell);
251     }
252
253 #if ENABLE(GGC)
254     inline void Heap::writeBarrierFastCase(const JSCell* owner, JSCell* cell)
255     {
256         if (MarkedBlock::blockFor(owner)->inNewSpace())
257             return;
258         writeBarrierSlowCase(owner, cell);
259     }
260
261     inline void Heap::writeBarrier(const JSCell* owner, JSCell* cell)
262     {
263         WriteBarrierCounters::countWriteBarrier();
264         writeBarrierFastCase(owner, cell);
265     }
266
267     inline void Heap::writeBarrier(const JSCell* owner, JSValue value)
268     {
269         WriteBarrierCounters::countWriteBarrier();
270         if (!value)
271             return;
272         if (!value.isCell())
273             return;
274         writeBarrierFastCase(owner, value.asCell());
275     }
276 #else
277
278     inline void Heap::writeBarrier(const JSCell*, JSCell*)
279     {
280         WriteBarrierCounters::countWriteBarrier();
281     }
282
283     inline void Heap::writeBarrier(const JSCell*, JSValue)
284     {
285         WriteBarrierCounters::countWriteBarrier();
286     }
287 #endif
288
289     inline void Heap::reportExtraMemoryCost(size_t cost)
290     {
291         if (cost > minExtraCost) 
292             reportExtraMemoryCostSlowCase(cost);
293     }
294
295     template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell(Functor& functor)
296     {
297         canonicalizeBlocks();
298         ProtectCountSet::iterator end = m_protectedValues.end();
299         for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it)
300             functor(it->first);
301         m_handleHeap.forEachStrongHandle(functor, m_protectedValues);
302
303         return functor.returnValue();
304     }
305
306     template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell()
307     {
308         Functor functor;
309         return forEachProtectedCell(functor);
310     }
311
312     template<typename Functor> inline typename Functor::ReturnType Heap::forEachCell(Functor& functor)
313     {
314         canonicalizeBlocks();
315         BlockIterator end = m_blocks.set().end();
316         for (BlockIterator it = m_blocks.set().begin(); it != end; ++it)
317             (*it)->forEachCell(functor);
318         return functor.returnValue();
319     }
320
321     template<typename Functor> inline typename Functor::ReturnType Heap::forEachCell()
322     {
323         Functor functor;
324         return forEachCell(functor);
325     }
326
327     template<typename Functor> inline typename Functor::ReturnType Heap::forEachBlock(Functor& functor)
328     {
329         canonicalizeBlocks();
330         BlockIterator end = m_blocks.set().end();
331         for (BlockIterator it = m_blocks.set().begin(); it != end; ++it)
332             functor(*it);
333         return functor.returnValue();
334     }
335
336     template<typename Functor> inline typename Functor::ReturnType Heap::forEachBlock()
337     {
338         Functor functor;
339         return forEachBlock(functor);
340     }
341     
342     inline NewSpace::SizeClass& Heap::sizeClassFor(size_t bytes)
343     {
344         return m_newSpace.sizeClassFor(bytes);
345     }
346     
347     inline void* Heap::allocate(NewSpace::SizeClass& sizeClass)
348     {
349         // This is a light-weight fast path to cover the most common case.
350         MarkedBlock::FreeCell* firstFreeCell = sizeClass.firstFreeCell;
351         if (UNLIKELY(!firstFreeCell))
352             return allocateSlowCase(sizeClass);
353         
354         sizeClass.firstFreeCell = firstFreeCell->next;
355         return firstFreeCell;
356     }
357
358     inline void* Heap::allocate(size_t bytes)
359     {
360         ASSERT(isValidAllocation(bytes));
361         NewSpace::SizeClass& sizeClass = sizeClassFor(bytes);
362         return allocate(sizeClass);
363     }
364
365     inline void* Heap::allocatePropertyStorage(size_t bytes)
366     {
367         ASSERT(!(bytes % sizeof(JSValue)));
368         if (bytes >= NewSpace::PropertyStorageNurserySize)
369             return fastMalloc(bytes);
370         if (void* result = m_newSpace.allocatePropertyStorage(bytes))
371             return result;
372         collect(DoNotSweep);
373         return m_newSpace.allocatePropertyStorage(bytes);
374     }
375     
376     inline bool Heap::inPropertyStorageNursery(void* ptr)
377     {
378         return m_newSpace.inPropertyStorageNursery(ptr);
379     }
380
381 } // namespace JSC
382
383 #endif // Heap_h