Refactor Heap allocation logic into separate AllocationSpace class
[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 "AllocationSpace.h"
26 #include "HandleHeap.h"
27 #include "HandleStack.h"
28 #include "MarkedBlock.h"
29 #include "MarkedBlockSet.h"
30 #include "MarkedSpace.h"
31 #include "SlotVisitor.h"
32 #include "WriteBarrierSupport.h"
33 #include <wtf/Forward.h>
34 #include <wtf/HashCountedSet.h>
35 #include <wtf/HashSet.h>
36
37 namespace JSC {
38
39     class GCActivityCallback;
40     class GlobalCodeBlock;
41     class Heap;
42     class HeapRootVisitor;
43     class JSCell;
44     class JSGlobalData;
45     class JSValue;
46     class LiveObjectIterator;
47     class MarkedArgumentBuffer;
48     class RegisterFile;
49     class UString;
50     class WeakGCHandlePool;
51     class SlotVisitor;
52
53     typedef std::pair<JSValue, UString> ValueStringPair;
54     typedef HashCountedSet<JSCell*> ProtectCountSet;
55     typedef HashCountedSet<const char*> TypeCountSet;
56
57     enum OperationInProgress { NoOperation, Allocation, Collection };
58     
59     // Heap size hint.
60     enum HeapSize { SmallHeap, LargeHeap };
61
62     class Heap {
63         WTF_MAKE_NONCOPYABLE(Heap);
64     public:
65         friend class JIT;
66         static Heap* heap(JSValue); // 0 for immediate values
67         static Heap* heap(JSCell*);
68
69         static bool isMarked(const void*);
70         static bool testAndSetMarked(const void*);
71         static bool testAndClearMarked(const void*);
72         static void setMarked(const void*);
73
74         static void writeBarrier(const JSCell*, JSValue);
75         static void writeBarrier(const JSCell*, JSCell*);
76
77         Heap(JSGlobalData*, HeapSize);
78         ~Heap();
79         void destroy(); // JSGlobalData must call destroy() before ~Heap().
80
81         JSGlobalData* globalData() const { return m_globalData; }
82         AllocationSpace& objectSpace() { return m_objectSpace; }
83         MachineThreads& machineThreads() { return m_machineThreads; }
84
85         GCActivityCallback* activityCallback();
86         void setActivityCallback(PassOwnPtr<GCActivityCallback>);
87
88         // true if an allocation or collection is in progress
89         inline bool isBusy();
90         
91         MarkedSpace::SizeClass& sizeClassForObject(size_t bytes) { return m_objectSpace.sizeClassFor(bytes); }
92         void* allocate(size_t);
93
94         void notifyIsSafeToCollect() { m_isSafeToCollect = true; }
95         void collectAllGarbage();
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         
119         HandleSlot allocateGlobalHandle() { return m_handleHeap.allocate(); }
120         HandleSlot allocateLocalHandle() { return m_handleStack.push(); }
121
122         HandleStack* handleStack() { return &m_handleStack; }
123         void getConservativeRegisterRoots(HashSet<JSCell*>& roots);
124
125     private:
126         friend class MarkedBlock;
127         friend class AllocationSpace;
128
129         static const size_t minExtraCost = 256;
130         static const size_t maxExtraCost = 1024 * 1024;
131         
132 #if ENABLE(GGC)
133         static void writeBarrierFastCase(const JSCell* owner, JSCell*);
134 #endif
135
136         bool isValidAllocation(size_t);
137         void reportExtraMemoryCostSlowCase(size_t);
138         void canonicalizeBlocks();
139         void resetAllocator();
140
141         void freeBlocks(MarkedBlock*);
142
143         void clearMarks();
144         void markRoots();
145         void markProtectedObjects(HeapRootVisitor&);
146         void markTempSortVectors(HeapRootVisitor&);
147         void harvestWeakReferences();
148         
149         enum SweepToggle { DoNotSweep, DoSweep };
150         void collect(SweepToggle);
151         void shrink();
152         void releaseFreeBlocks();
153         void sweep();
154
155         RegisterFile& registerFile();
156
157         static void writeBarrierSlowCase(const JSCell*, JSCell*);
158
159         void waitForRelativeTimeWhileHoldingLock(double relative);
160         void waitForRelativeTime(double relative);
161         void blockFreeingThreadMain();
162         static void* blockFreeingThreadStartFunc(void* heap);
163
164         const HeapSize m_heapSize;
165         const size_t m_minBytesPerCycle;
166         
167         OperationInProgress m_operationInProgress;
168         AllocationSpace m_objectSpace;
169
170         DoublyLinkedList<MarkedBlock> m_freeBlocks;
171         size_t m_numberOfFreeBlocks;
172         
173         ThreadIdentifier m_blockFreeingThread;
174         Mutex m_freeBlockLock;
175         ThreadCondition m_freeBlockCondition;
176         bool m_blockFreeingThreadShouldQuit;
177
178 #if ENABLE(SIMPLE_HEAP_PROFILING)
179         VTableSpectrum m_destroyedTypeCounts;
180 #endif
181
182         size_t m_extraCost;
183
184         ProtectCountSet m_protectedValues;
185         Vector<Vector<ValueStringPair>* > m_tempSortingVectors;
186         HashSet<MarkedArgumentBuffer*>* m_markListSet;
187
188         OwnPtr<GCActivityCallback> m_activityCallback;
189         
190         MachineThreads m_machineThreads;
191         SlotVisitor m_slotVisitor;
192         HandleHeap m_handleHeap;
193         HandleStack m_handleStack;
194         
195         bool m_isSafeToCollect;
196
197         JSGlobalData* m_globalData;
198     };
199
200     bool Heap::isBusy()
201     {
202         return m_operationInProgress != NoOperation;
203     }
204
205     inline Heap* Heap::heap(JSCell* cell)
206     {
207         return MarkedBlock::blockFor(cell)->heap();
208     }
209
210     inline Heap* Heap::heap(JSValue v)
211     {
212         if (!v.isCell())
213             return 0;
214         return heap(v.asCell());
215     }
216
217     inline bool Heap::isMarked(const void* cell)
218     {
219         return MarkedBlock::blockFor(cell)->isMarked(cell);
220     }
221
222     inline bool Heap::testAndSetMarked(const void* cell)
223     {
224         return MarkedBlock::blockFor(cell)->testAndSetMarked(cell);
225     }
226
227     inline bool Heap::testAndClearMarked(const void* cell)
228     {
229         return MarkedBlock::blockFor(cell)->testAndClearMarked(cell);
230     }
231
232     inline void Heap::setMarked(const void* cell)
233     {
234         MarkedBlock::blockFor(cell)->setMarked(cell);
235     }
236
237 #if ENABLE(GGC)
238     inline void Heap::writeBarrierFastCase(const JSCell* owner, JSCell* cell)
239     {
240         if (MarkedBlock::blockFor(owner)->inNewSpace())
241             return;
242         writeBarrierSlowCase(owner, cell);
243     }
244
245     inline void Heap::writeBarrier(const JSCell* owner, JSCell* cell)
246     {
247         WriteBarrierCounters::countWriteBarrier();
248         writeBarrierFastCase(owner, cell);
249     }
250
251     inline void Heap::writeBarrier(const JSCell* owner, JSValue value)
252     {
253         WriteBarrierCounters::countWriteBarrier();
254         if (!value)
255             return;
256         if (!value.isCell())
257             return;
258         writeBarrierFastCase(owner, value.asCell());
259     }
260 #else
261
262     inline void Heap::writeBarrier(const JSCell*, JSCell*)
263     {
264         WriteBarrierCounters::countWriteBarrier();
265     }
266
267     inline void Heap::writeBarrier(const JSCell*, JSValue)
268     {
269         WriteBarrierCounters::countWriteBarrier();
270     }
271 #endif
272
273     inline void Heap::reportExtraMemoryCost(size_t cost)
274     {
275         if (cost > minExtraCost) 
276             reportExtraMemoryCostSlowCase(cost);
277     }
278
279     template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell(Functor& functor)
280     {
281         canonicalizeBlocks();
282         ProtectCountSet::iterator end = m_protectedValues.end();
283         for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it)
284             functor(it->first);
285         m_handleHeap.forEachStrongHandle(functor, m_protectedValues);
286
287         return functor.returnValue();
288     }
289
290     template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell()
291     {
292         Functor functor;
293         return forEachProtectedCell(functor);
294     }
295
296     inline void* Heap::allocate(size_t bytes)
297     {
298         ASSERT(isValidAllocation(bytes));
299         return m_objectSpace.allocate(bytes);
300     }
301
302 } // namespace JSC
303
304 #endif // Heap_h