3d308b36abda117d7f47d240fc99e748f1eaeffa
[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 "MarkedSpace.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         MarkedSpace& markedSpace() { return m_markedSpace; }
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         MarkedSpace::SizeClass& sizeClassFor(size_t);
90         void* allocate(MarkedSpace::SizeClass&);
91         void notifyIsSafeToCollect() { m_isSafeToCollect = true; }
92         void collectAllGarbage();
93
94         void reportExtraMemoryCost(size_t cost);
95
96         void protect(JSValue);
97         bool unprotect(JSValue); // True when the protect count drops to 0.
98
99         size_t size();
100         size_t capacity();
101         size_t objectCount();
102         size_t globalObjectCount();
103         size_t protectedObjectCount();
104         size_t protectedGlobalObjectCount();
105         PassOwnPtr<TypeCountSet> protectedObjectTypeCounts();
106         PassOwnPtr<TypeCountSet> objectTypeCounts();
107
108         void pushTempSortVector(Vector<ValueStringPair>*);
109         void popTempSortVector(Vector<ValueStringPair>*);
110     
111         HashSet<MarkedArgumentBuffer*>& markListSet() { if (!m_markListSet) m_markListSet = new HashSet<MarkedArgumentBuffer*>; return *m_markListSet; }
112         
113         template<typename Functor> typename Functor::ReturnType forEachProtectedCell(Functor&);
114         template<typename Functor> typename Functor::ReturnType forEachProtectedCell();
115         template<typename Functor> typename Functor::ReturnType forEachCell(Functor&);
116         template<typename Functor> typename Functor::ReturnType forEachCell();
117         template<typename Functor> typename Functor::ReturnType forEachBlock(Functor&);
118         template<typename Functor> typename Functor::ReturnType forEachBlock();
119         
120         HandleSlot allocateGlobalHandle() { return m_handleHeap.allocate(); }
121         HandleSlot allocateLocalHandle() { return m_handleStack.push(); }
122
123         HandleStack* handleStack() { return &m_handleStack; }
124         void getConservativeRegisterRoots(HashSet<JSCell*>& roots);
125
126     private:
127         friend class MarkedBlock;
128         
129         typedef HashSet<MarkedBlock*>::iterator BlockIterator;
130
131         static const size_t minExtraCost = 256;
132         static const size_t maxExtraCost = 1024 * 1024;
133         
134         enum AllocationEffort { AllocationMustSucceed, AllocationCanFail };
135         
136 #if ENABLE(GGC)
137         static void writeBarrierFastCase(const JSCell* owner, JSCell*);
138 #endif
139
140         bool isValidAllocation(size_t);
141         void reportExtraMemoryCostSlowCase(size_t);
142         void canonicalizeBlocks();
143         void resetAllocator();
144
145         MarkedBlock* allocateBlock(size_t cellSize, AllocationEffort);
146         void freeBlocks(MarkedBlock*);
147
148         void clearMarks();
149         void markRoots();
150         void markProtectedObjects(HeapRootVisitor&);
151         void markTempSortVectors(HeapRootVisitor&);
152         void harvestWeakReferences();
153
154         void* tryAllocate(MarkedSpace::SizeClass&);
155         void* allocateSlowCase(MarkedSpace::SizeClass&);
156         
157         enum SweepToggle { DoNotSweep, DoSweep };
158         void collect(SweepToggle);
159         void shrink();
160         void releaseFreeBlocks();
161         void sweep();
162
163         RegisterFile& registerFile();
164
165         static void writeBarrierSlowCase(const JSCell*, JSCell*);
166
167 #if ENABLE(LAZY_BLOCK_FREEING)
168         void waitForRelativeTimeWhileHoldingLock(double relative);
169         void waitForRelativeTime(double relative);
170         void blockFreeingThreadMain();
171         static void* blockFreeingThreadStartFunc(void* heap);
172 #endif
173
174         const HeapSize m_heapSize;
175         const size_t m_minBytesPerCycle;
176         
177         OperationInProgress m_operationInProgress;
178         MarkedSpace m_markedSpace;
179         MarkedBlockSet m_blocks;
180
181 #if ENABLE(LAZY_BLOCK_FREEING)
182         DoublyLinkedList<MarkedBlock> m_freeBlocks;
183         size_t m_numberOfFreeBlocks;
184         
185         ThreadIdentifier m_blockFreeingThread;
186         Mutex m_freeBlockLock;
187         ThreadCondition m_freeBlockCondition;
188         bool m_blockFreeingThreadShouldQuit;
189 #endif
190
191 #if ENABLE(SIMPLE_HEAP_PROFILING)
192         VTableSpectrum m_destroyedTypeCounts;
193 #endif
194
195         size_t m_extraCost;
196
197         ProtectCountSet m_protectedValues;
198         Vector<Vector<ValueStringPair>* > m_tempSortingVectors;
199         HashSet<MarkedArgumentBuffer*>* m_markListSet;
200
201         OwnPtr<GCActivityCallback> m_activityCallback;
202         
203         MachineThreads m_machineThreads;
204         SlotVisitor m_slotVisitor;
205         HandleHeap m_handleHeap;
206         HandleStack m_handleStack;
207         
208         bool m_isSafeToCollect;
209
210         JSGlobalData* m_globalData;
211     };
212
213     bool Heap::isBusy()
214     {
215         return m_operationInProgress != NoOperation;
216     }
217
218     inline Heap* Heap::heap(JSCell* cell)
219     {
220         return MarkedBlock::blockFor(cell)->heap();
221     }
222
223     inline Heap* Heap::heap(JSValue v)
224     {
225         if (!v.isCell())
226             return 0;
227         return heap(v.asCell());
228     }
229
230     inline bool Heap::isMarked(const void* cell)
231     {
232         return MarkedBlock::blockFor(cell)->isMarked(cell);
233     }
234
235     inline bool Heap::testAndSetMarked(const void* cell)
236     {
237         return MarkedBlock::blockFor(cell)->testAndSetMarked(cell);
238     }
239
240     inline bool Heap::testAndClearMarked(const void* cell)
241     {
242         return MarkedBlock::blockFor(cell)->testAndClearMarked(cell);
243     }
244
245     inline void Heap::setMarked(const void* cell)
246     {
247         MarkedBlock::blockFor(cell)->setMarked(cell);
248     }
249
250 #if ENABLE(GGC)
251     inline void Heap::writeBarrierFastCase(const JSCell* owner, JSCell* cell)
252     {
253         if (MarkedBlock::blockFor(owner)->inNewSpace())
254             return;
255         writeBarrierSlowCase(owner, cell);
256     }
257
258     inline void Heap::writeBarrier(const JSCell* owner, JSCell* cell)
259     {
260         WriteBarrierCounters::countWriteBarrier();
261         writeBarrierFastCase(owner, cell);
262     }
263
264     inline void Heap::writeBarrier(const JSCell* owner, JSValue value)
265     {
266         WriteBarrierCounters::countWriteBarrier();
267         if (!value)
268             return;
269         if (!value.isCell())
270             return;
271         writeBarrierFastCase(owner, value.asCell());
272     }
273 #else
274
275     inline void Heap::writeBarrier(const JSCell*, JSCell*)
276     {
277         WriteBarrierCounters::countWriteBarrier();
278     }
279
280     inline void Heap::writeBarrier(const JSCell*, JSValue)
281     {
282         WriteBarrierCounters::countWriteBarrier();
283     }
284 #endif
285
286     inline void Heap::reportExtraMemoryCost(size_t cost)
287     {
288         if (cost > minExtraCost) 
289             reportExtraMemoryCostSlowCase(cost);
290     }
291
292     template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell(Functor& functor)
293     {
294         canonicalizeBlocks();
295         ProtectCountSet::iterator end = m_protectedValues.end();
296         for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it)
297             functor(it->first);
298         m_handleHeap.forEachStrongHandle(functor, m_protectedValues);
299
300         return functor.returnValue();
301     }
302
303     template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell()
304     {
305         Functor functor;
306         return forEachProtectedCell(functor);
307     }
308
309     template<typename Functor> inline typename Functor::ReturnType Heap::forEachCell(Functor& functor)
310     {
311         canonicalizeBlocks();
312         BlockIterator end = m_blocks.set().end();
313         for (BlockIterator it = m_blocks.set().begin(); it != end; ++it)
314             (*it)->forEachCell(functor);
315         return functor.returnValue();
316     }
317
318     template<typename Functor> inline typename Functor::ReturnType Heap::forEachCell()
319     {
320         Functor functor;
321         return forEachCell(functor);
322     }
323
324     template<typename Functor> inline typename Functor::ReturnType Heap::forEachBlock(Functor& functor)
325     {
326         canonicalizeBlocks();
327         BlockIterator end = m_blocks.set().end();
328         for (BlockIterator it = m_blocks.set().begin(); it != end; ++it)
329             functor(*it);
330         return functor.returnValue();
331     }
332
333     template<typename Functor> inline typename Functor::ReturnType Heap::forEachBlock()
334     {
335         Functor functor;
336         return forEachBlock(functor);
337     }
338     
339     inline MarkedSpace::SizeClass& Heap::sizeClassFor(size_t bytes)
340     {
341         return m_markedSpace.sizeClassFor(bytes);
342     }
343     
344     inline void* Heap::allocate(MarkedSpace::SizeClass& sizeClass)
345     {
346         // This is a light-weight fast path to cover the most common case.
347         MarkedBlock::FreeCell* firstFreeCell = sizeClass.firstFreeCell;
348         if (UNLIKELY(!firstFreeCell))
349             return allocateSlowCase(sizeClass);
350         
351         sizeClass.firstFreeCell = firstFreeCell->next;
352         return firstFreeCell;
353     }
354
355     inline void* Heap::allocate(size_t bytes)
356     {
357         ASSERT(isValidAllocation(bytes));
358         MarkedSpace::SizeClass& sizeClass = sizeClassFor(bytes);
359         return allocate(sizeClass);
360     }
361
362 } // namespace JSC
363
364 #endif // Heap_h