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 #if ENABLE(LAZY_BLOCK_FREEING)
160         void waitForRelativeTimeWhileHoldingLock(double relative);
161         void waitForRelativeTime(double relative);
162         void blockFreeingThreadMain();
163         static void* blockFreeingThreadStartFunc(void* heap);
164 #endif
165
166         const HeapSize m_heapSize;
167         const size_t m_minBytesPerCycle;
168         
169         OperationInProgress m_operationInProgress;
170         AllocationSpace m_objectSpace;
171
172 #if ENABLE(LAZY_BLOCK_FREEING)
173         DoublyLinkedList<MarkedBlock> m_freeBlocks;
174         size_t m_numberOfFreeBlocks;
175         
176         ThreadIdentifier m_blockFreeingThread;
177         Mutex m_freeBlockLock;
178         ThreadCondition m_freeBlockCondition;
179         bool m_blockFreeingThreadShouldQuit;
180 #endif
181
182 #if ENABLE(SIMPLE_HEAP_PROFILING)
183         VTableSpectrum m_destroyedTypeCounts;
184 #endif
185
186         size_t m_extraCost;
187
188         ProtectCountSet m_protectedValues;
189         Vector<Vector<ValueStringPair>* > m_tempSortingVectors;
190         HashSet<MarkedArgumentBuffer*>* m_markListSet;
191
192         OwnPtr<GCActivityCallback> m_activityCallback;
193         
194         MachineThreads m_machineThreads;
195         SlotVisitor m_slotVisitor;
196         HandleHeap m_handleHeap;
197         HandleStack m_handleStack;
198         
199         bool m_isSafeToCollect;
200
201         JSGlobalData* m_globalData;
202     };
203
204     bool Heap::isBusy()
205     {
206         return m_operationInProgress != NoOperation;
207     }
208
209     inline Heap* Heap::heap(JSCell* cell)
210     {
211         return MarkedBlock::blockFor(cell)->heap();
212     }
213
214     inline Heap* Heap::heap(JSValue v)
215     {
216         if (!v.isCell())
217             return 0;
218         return heap(v.asCell());
219     }
220
221     inline bool Heap::isMarked(const void* cell)
222     {
223         return MarkedBlock::blockFor(cell)->isMarked(cell);
224     }
225
226     inline bool Heap::testAndSetMarked(const void* cell)
227     {
228         return MarkedBlock::blockFor(cell)->testAndSetMarked(cell);
229     }
230
231     inline bool Heap::testAndClearMarked(const void* cell)
232     {
233         return MarkedBlock::blockFor(cell)->testAndClearMarked(cell);
234     }
235
236     inline void Heap::setMarked(const void* cell)
237     {
238         MarkedBlock::blockFor(cell)->setMarked(cell);
239     }
240
241 #if ENABLE(GGC)
242     inline void Heap::writeBarrierFastCase(const JSCell* owner, JSCell* cell)
243     {
244         if (MarkedBlock::blockFor(owner)->inNewSpace())
245             return;
246         writeBarrierSlowCase(owner, cell);
247     }
248
249     inline void Heap::writeBarrier(const JSCell* owner, JSCell* cell)
250     {
251         WriteBarrierCounters::countWriteBarrier();
252         writeBarrierFastCase(owner, cell);
253     }
254
255     inline void Heap::writeBarrier(const JSCell* owner, JSValue value)
256     {
257         WriteBarrierCounters::countWriteBarrier();
258         if (!value)
259             return;
260         if (!value.isCell())
261             return;
262         writeBarrierFastCase(owner, value.asCell());
263     }
264 #else
265
266     inline void Heap::writeBarrier(const JSCell*, JSCell*)
267     {
268         WriteBarrierCounters::countWriteBarrier();
269     }
270
271     inline void Heap::writeBarrier(const JSCell*, JSValue)
272     {
273         WriteBarrierCounters::countWriteBarrier();
274     }
275 #endif
276
277     inline void Heap::reportExtraMemoryCost(size_t cost)
278     {
279         if (cost > minExtraCost) 
280             reportExtraMemoryCostSlowCase(cost);
281     }
282
283     template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell(Functor& functor)
284     {
285         canonicalizeBlocks();
286         ProtectCountSet::iterator end = m_protectedValues.end();
287         for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it)
288             functor(it->first);
289         m_handleHeap.forEachStrongHandle(functor, m_protectedValues);
290
291         return functor.returnValue();
292     }
293
294     template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell()
295     {
296         Functor functor;
297         return forEachProtectedCell(functor);
298     }
299
300     inline void* Heap::allocate(size_t bytes)
301     {
302         ASSERT(isValidAllocation(bytes));
303         return m_objectSpace.allocate(bytes);
304     }
305
306 } // namespace JSC
307
308 #endif // Heap_h