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.
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.
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.
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
25 #include "AllocationSpace.h"
26 #include "DFGCodeBlocks.h"
27 #include "HandleHeap.h"
28 #include "HandleStack.h"
29 #include "MarkedBlock.h"
30 #include "MarkedBlockSet.h"
31 #include "MarkedSpace.h"
32 #include "SlotVisitor.h"
33 #include "WriteBarrierSupport.h"
34 #include <wtf/Forward.h>
35 #include <wtf/HashCountedSet.h>
36 #include <wtf/HashSet.h>
41 class GCActivityCallback;
42 class GlobalCodeBlock;
44 class HeapRootVisitor;
48 class LiveObjectIterator;
49 class MarkedArgumentBuffer;
52 class WeakGCHandlePool;
55 typedef std::pair<JSValue, UString> ValueStringPair;
56 typedef HashCountedSet<JSCell*> ProtectCountSet;
57 typedef HashCountedSet<const char*> TypeCountSet;
59 enum OperationInProgress { NoOperation, Allocation, Collection };
62 enum HeapSize { SmallHeap, LargeHeap };
65 WTF_MAKE_NONCOPYABLE(Heap);
68 static Heap* heap(JSValue); // 0 for immediate values
69 static Heap* heap(JSCell*);
71 static bool isMarked(const void*);
72 static bool testAndSetMarked(const void*);
73 static void setMarked(const void*);
75 static void writeBarrier(const JSCell*, JSValue);
76 static void writeBarrier(const JSCell*, JSCell*);
77 static uint8_t* addressOfCardFor(JSCell*);
79 Heap(JSGlobalData*, HeapSize);
81 void destroy(); // JSGlobalData must call destroy() before ~Heap().
83 JSGlobalData* globalData() const { return m_globalData; }
84 AllocationSpace& objectSpace() { return m_objectSpace; }
85 MachineThreads& machineThreads() { return m_machineThreads; }
87 GCActivityCallback* activityCallback();
88 void setActivityCallback(PassOwnPtr<GCActivityCallback>);
90 // true if an allocation or collection is in progress
93 MarkedSpace::SizeClass& sizeClassForObject(size_t bytes) { return m_objectSpace.sizeClassFor(bytes); }
94 void* allocate(size_t);
96 typedef void (*Finalizer)(JSCell*);
97 void addFinalizer(JSCell*, Finalizer);
99 void notifyIsSafeToCollect() { m_isSafeToCollect = true; }
100 void collectAllGarbage();
102 void reportExtraMemoryCost(size_t cost);
104 void protect(JSValue);
105 bool unprotect(JSValue); // True when the protect count drops to 0.
107 void jettisonDFGCodeBlock(PassOwnPtr<CodeBlock>);
111 size_t objectCount();
112 size_t globalObjectCount();
113 size_t protectedObjectCount();
114 size_t protectedGlobalObjectCount();
115 PassOwnPtr<TypeCountSet> protectedObjectTypeCounts();
116 PassOwnPtr<TypeCountSet> objectTypeCounts();
118 void pushTempSortVector(Vector<ValueStringPair>*);
119 void popTempSortVector(Vector<ValueStringPair>*);
121 HashSet<MarkedArgumentBuffer*>& markListSet() { if (!m_markListSet) m_markListSet = new HashSet<MarkedArgumentBuffer*>; return *m_markListSet; }
123 template<typename Functor> typename Functor::ReturnType forEachProtectedCell(Functor&);
124 template<typename Functor> typename Functor::ReturnType forEachProtectedCell();
126 HandleHeap* handleHeap() { return &m_handleHeap; }
127 HandleStack* handleStack() { return &m_handleStack; }
129 void getConservativeRegisterRoots(HashSet<JSCell*>& roots);
132 friend class MarkedBlock;
133 friend class AllocationSpace;
134 friend class SlotVisitor;
135 friend class CodeBlock;
137 static const size_t minExtraCost = 256;
138 static const size_t maxExtraCost = 1024 * 1024;
140 class FinalizerOwner : public WeakHandleOwner {
141 virtual void finalize(Handle<Unknown>, void* context);
144 bool isValidAllocation(size_t);
145 void reportExtraMemoryCostSlowCase(size_t);
147 // Call this function before any operation that needs to know which cells
148 // in the heap are live. (For example, call this function before
149 // conservative marking, eager sweeping, or iterating the cells in a MarkedBlock.)
150 void canonicalizeCellLivenessData();
152 void resetAllocator();
153 void freeBlocks(MarkedBlock*);
156 void markRoots(bool fullGC);
157 void markProtectedObjects(HeapRootVisitor&);
158 void markTempSortVectors(HeapRootVisitor&);
159 void harvestWeakReferences();
160 void finalizeUnconditionalFinalizers();
162 enum SweepToggle { DoNotSweep, DoSweep };
163 void collect(SweepToggle);
165 void releaseFreeBlocks();
168 RegisterFile& registerFile();
170 void waitForRelativeTimeWhileHoldingLock(double relative);
171 void waitForRelativeTime(double relative);
172 void blockFreeingThreadMain();
173 static void* blockFreeingThreadStartFunc(void* heap);
175 const HeapSize m_heapSize;
176 const size_t m_minBytesPerCycle;
177 size_t m_lastFullGCSize;
179 OperationInProgress m_operationInProgress;
180 AllocationSpace m_objectSpace;
182 DoublyLinkedList<MarkedBlock> m_freeBlocks;
183 size_t m_numberOfFreeBlocks;
185 ThreadIdentifier m_blockFreeingThread;
186 Mutex m_freeBlockLock;
187 ThreadCondition m_freeBlockCondition;
188 bool m_blockFreeingThreadShouldQuit;
190 #if ENABLE(SIMPLE_HEAP_PROFILING)
191 VTableSpectrum m_destroyedTypeCounts;
196 ProtectCountSet m_protectedValues;
197 Vector<Vector<ValueStringPair>* > m_tempSortingVectors;
198 HashSet<MarkedArgumentBuffer*>* m_markListSet;
200 OwnPtr<GCActivityCallback> m_activityCallback;
202 MachineThreads m_machineThreads;
204 MarkStackThreadSharedData m_sharedData;
205 SlotVisitor m_slotVisitor;
207 HandleHeap m_handleHeap;
208 HandleStack m_handleStack;
209 DFGCodeBlocks m_dfgCodeBlocks;
210 FinalizerOwner m_finalizerOwner;
212 bool m_isSafeToCollect;
214 JSGlobalData* m_globalData;
219 return m_operationInProgress != NoOperation;
222 inline Heap* Heap::heap(JSCell* cell)
224 return MarkedBlock::blockFor(cell)->heap();
227 inline Heap* Heap::heap(JSValue v)
231 return heap(v.asCell());
234 inline bool Heap::isMarked(const void* cell)
236 return MarkedBlock::blockFor(cell)->isMarked(cell);
239 inline bool Heap::testAndSetMarked(const void* cell)
241 return MarkedBlock::blockFor(cell)->testAndSetMarked(cell);
244 inline void Heap::setMarked(const void* cell)
246 MarkedBlock::blockFor(cell)->setMarked(cell);
250 inline uint8_t* Heap::addressOfCardFor(JSCell* cell)
252 return MarkedBlock::blockFor(cell)->addressOfCardFor(cell);
255 inline void Heap::writeBarrier(const JSCell* owner, JSCell*)
257 WriteBarrierCounters::countWriteBarrier();
258 MarkedBlock* block = MarkedBlock::blockFor(owner);
259 if (block->isMarked(owner))
260 block->setDirtyObject(owner);
263 inline void Heap::writeBarrier(const JSCell* owner, JSValue value)
269 writeBarrier(owner, value.asCell());
273 inline void Heap::writeBarrier(const JSCell*, JSCell*)
275 WriteBarrierCounters::countWriteBarrier();
278 inline void Heap::writeBarrier(const JSCell*, JSValue)
280 WriteBarrierCounters::countWriteBarrier();
284 inline void Heap::reportExtraMemoryCost(size_t cost)
286 if (cost > minExtraCost)
287 reportExtraMemoryCostSlowCase(cost);
290 template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell(Functor& functor)
292 ProtectCountSet::iterator end = m_protectedValues.end();
293 for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it)
295 m_handleHeap.forEachStrongHandle(functor, m_protectedValues);
297 return functor.returnValue();
300 template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell()
303 return forEachProtectedCell(functor);
306 inline void* Heap::allocate(size_t bytes)
308 ASSERT(isValidAllocation(bytes));
309 return m_objectSpace.allocate(bytes);