#ifndef Heap_h
#define Heap_h
-#include "HandleHeap.h"
+#include "BlockAllocator.h"
+#include "DFGCodeBlocks.h"
+#include "HandleSet.h"
#include "HandleStack.h"
-#include "MarkStack.h"
+#include "MarkedAllocator.h"
+#include "MarkedBlock.h"
+#include "MarkedBlockSet.h"
#include "MarkedSpace.h"
-#include <wtf/Forward.h>
+#include "SlotVisitor.h"
+#include "WeakHandleOwner.h"
+#include "WeakSet.h"
+#include "WriteBarrierSupport.h"
#include <wtf/HashCountedSet.h>
#include <wtf/HashSet.h>
+#define COLLECT_ON_EVERY_ALLOCATION 0
+
namespace JSC {
+ class CopiedSpace;
+ class CodeBlock;
+ class FunctionExecutable;
class GCActivityCallback;
class GlobalCodeBlock;
+ class Heap;
class HeapRootVisitor;
class JSCell;
class JSGlobalData;
class JSValue;
class LiveObjectIterator;
- class MarkStack;
+ class LLIntOffsetsExtractor;
class MarkedArgumentBuffer;
class RegisterFile;
class UString;
class WeakGCHandlePool;
- typedef MarkStack SlotVisitor;
+ class SlotVisitor;
typedef std::pair<JSValue, UString> ValueStringPair;
typedef HashCountedSet<JSCell*> ProtectCountSet;
enum OperationInProgress { NoOperation, Allocation, Collection };
+ // Heap size hint.
+ enum HeapSize { SmallHeap, LargeHeap };
+
class Heap {
WTF_MAKE_NONCOPYABLE(Heap);
public:
- static Heap* heap(JSValue); // 0 for immediate values
- static Heap* heap(JSCell*);
+ friend class JIT;
+ friend class MarkStackThreadSharedData;
+ static Heap* heap(const JSValue); // 0 for immediate values
+ static Heap* heap(const JSCell*);
+
+ // This constant determines how many blocks we iterate between checks of our
+ // deadline when calling Heap::isPagedOut. Decreasing it will cause us to detect
+ // overstepping our deadline more quickly, while increasing it will cause
+ // our scan to run faster.
+ static const unsigned s_timeCheckResolution = 16;
- static bool isMarked(const JSCell*);
- static bool testAndSetMarked(const JSCell*);
- static void setMarked(JSCell*);
+ static bool isMarked(const void*);
+ static bool testAndSetMarked(const void*);
+ static void setMarked(const void*);
static void writeBarrier(const JSCell*, JSValue);
static void writeBarrier(const JSCell*, JSCell*);
+ static uint8_t* addressOfCardFor(JSCell*);
- Heap(JSGlobalData*);
+ Heap(JSGlobalData*, HeapSize);
~Heap();
- void destroy(); // JSGlobalData must call destroy() before ~Heap().
+ JS_EXPORT_PRIVATE void lastChanceToFinalize();
JSGlobalData* globalData() const { return m_globalData; }
- MarkedSpace& markedSpace() { return m_markedSpace; }
+ MarkedSpace& objectSpace() { return m_objectSpace; }
MachineThreads& machineThreads() { return m_machineThreads; }
- GCActivityCallback* activityCallback();
- void setActivityCallback(PassOwnPtr<GCActivityCallback>);
+ JS_EXPORT_PRIVATE GCActivityCallback* activityCallback();
+ JS_EXPORT_PRIVATE void setActivityCallback(GCActivityCallback*);
// true if an allocation or collection is in progress
inline bool isBusy();
+
+ MarkedAllocator& firstAllocatorWithoutDestructors() { return m_objectSpace.firstAllocator(); }
+ MarkedAllocator& allocatorForObjectWithoutDestructor(size_t bytes) { return m_objectSpace.allocatorFor(bytes); }
+ MarkedAllocator& allocatorForObjectWithDestructor(size_t bytes) { return m_objectSpace.destructorAllocatorFor(bytes); }
+ CopiedAllocator& storageAllocator() { return m_storageSpace.allocator(); }
+ CheckedBoolean tryAllocateStorage(size_t, void**);
+ CheckedBoolean tryReallocateStorage(void**, size_t, size_t);
- void* allocate(size_t);
- void collectAllGarbage();
+ typedef void (*Finalizer)(JSCell*);
+ JS_EXPORT_PRIVATE void addFinalizer(JSCell*, Finalizer);
+ void addFunctionExecutable(FunctionExecutable*);
+ void removeFunctionExecutable(FunctionExecutable*);
- void reportExtraMemoryCost(size_t cost);
+ void notifyIsSafeToCollect() { m_isSafeToCollect = true; }
- void protect(JSValue);
- bool unprotect(JSValue); // True when the protect count drops to 0.
+ JS_EXPORT_PRIVATE void collectAllGarbage();
+ enum SweepToggle { DoNotSweep, DoSweep };
+ bool shouldCollect();
+ void collect(SweepToggle);
+
+ void reportExtraMemoryCost(size_t cost);
+ JS_EXPORT_PRIVATE void reportAbandonedObjectGraph();
- bool contains(void*);
+ JS_EXPORT_PRIVATE void protect(JSValue);
+ JS_EXPORT_PRIVATE bool unprotect(JSValue); // True when the protect count drops to 0.
+
+ void jettisonDFGCodeBlock(PassOwnPtr<CodeBlock>);
- size_t size() const;
- size_t capacity() const;
- size_t objectCount() const;
- size_t globalObjectCount();
- size_t protectedObjectCount();
- size_t protectedGlobalObjectCount();
- PassOwnPtr<TypeCountSet> protectedObjectTypeCounts();
- PassOwnPtr<TypeCountSet> objectTypeCounts();
+ JS_EXPORT_PRIVATE size_t size();
+ JS_EXPORT_PRIVATE size_t capacity();
+ JS_EXPORT_PRIVATE size_t objectCount();
+ JS_EXPORT_PRIVATE size_t globalObjectCount();
+ JS_EXPORT_PRIVATE size_t protectedObjectCount();
+ JS_EXPORT_PRIVATE size_t protectedGlobalObjectCount();
+ JS_EXPORT_PRIVATE PassOwnPtr<TypeCountSet> protectedObjectTypeCounts();
+ JS_EXPORT_PRIVATE PassOwnPtr<TypeCountSet> objectTypeCounts();
void pushTempSortVector(Vector<ValueStringPair>*);
void popTempSortVector(Vector<ValueStringPair>*);
HashSet<MarkedArgumentBuffer*>& markListSet() { if (!m_markListSet) m_markListSet = new HashSet<MarkedArgumentBuffer*>; return *m_markListSet; }
- template <typename Functor> void forEach(Functor&);
-
- HandleSlot allocateGlobalHandle() { return m_handleHeap.allocate(); }
- HandleSlot allocateLocalHandle() { return m_handleStack.push(); }
+ template<typename Functor> typename Functor::ReturnType forEachProtectedCell(Functor&);
+ template<typename Functor> typename Functor::ReturnType forEachProtectedCell();
+ WeakSet* weakSet() { return &m_weakSet; }
+ HandleSet* handleSet() { return &m_handleSet; }
HandleStack* handleStack() { return &m_handleStack; }
+
void getConservativeRegisterRoots(HashSet<JSCell*>& roots);
+ double lastGCLength() { return m_lastGCLength; }
+ void increaseLastGCLength(double amount) { m_lastGCLength += amount; }
+
+ JS_EXPORT_PRIVATE void discardAllCompiledCode();
+
+ void didAllocate(size_t);
+ void didAbandon(size_t);
+
+ bool isPagedOut(double deadline);
+
private:
- friend class JSGlobalData;
+ friend class CodeBlock;
+ friend class LLIntOffsetsExtractor;
+ friend class MarkedSpace;
+ friend class MarkedAllocator;
+ friend class MarkedBlock;
+ friend class CopiedSpace;
+ friend class SlotVisitor;
+ template<typename T> friend void* allocateCell(Heap&);
+
+ void* allocateWithDestructor(size_t);
+ void* allocateWithoutDestructor(size_t);
static const size_t minExtraCost = 256;
static const size_t maxExtraCost = 1024 * 1024;
+
+ class FinalizerOwner : public WeakHandleOwner {
+ virtual void finalize(Handle<Unknown>, void* context);
+ };
+
+ JS_EXPORT_PRIVATE bool isValidAllocation(size_t);
+ JS_EXPORT_PRIVATE void reportExtraMemoryCostSlowCase(size_t);
+
+ // Call this function before any operation that needs to know which cells
+ // in the heap are live. (For example, call this function before
+ // conservative marking, eager sweeping, or iterating the cells in a MarkedBlock.)
+ void canonicalizeCellLivenessData();
- void* allocateSlowCase(size_t);
- void reportExtraMemoryCostSlowCase(size_t);
+ void resetAllocators();
- void markRoots();
+ void clearMarks();
+ void markRoots(bool fullGC);
void markProtectedObjects(HeapRootVisitor&);
void markTempSortVectors(HeapRootVisitor&);
-
- enum SweepToggle { DoNotSweep, DoSweep };
- void reset(SweepToggle);
+ void harvestWeakReferences();
+ void finalizeUnconditionalFinalizers();
+
+ void sweep();
RegisterFile& registerFile();
+ BlockAllocator& blockAllocator();
+ const HeapSize m_heapSize;
+ const size_t m_minBytesPerCycle;
+ size_t m_sizeAfterLastCollect;
+
+ size_t m_bytesAllocatedLimit;
+ size_t m_bytesAllocated;
+ size_t m_bytesAbandoned;
+
OperationInProgress m_operationInProgress;
- MarkedSpace m_markedSpace;
+ MarkedSpace m_objectSpace;
+ CopiedSpace m_storageSpace;
+
+ BlockAllocator m_blockAllocator;
+
+#if ENABLE(SIMPLE_HEAP_PROFILING)
+ VTableSpectrum m_destroyedTypeCounts;
+#endif
ProtectCountSet m_protectedValues;
Vector<Vector<ValueStringPair>* > m_tempSortingVectors;
-
HashSet<MarkedArgumentBuffer*>* m_markListSet;
- OwnPtr<GCActivityCallback> m_activityCallback;
-
- JSGlobalData* m_globalData;
-
MachineThreads m_machineThreads;
- MarkStack m_markStack;
- HandleHeap m_handleHeap;
+
+ MarkStackThreadSharedData m_sharedData;
+ SlotVisitor m_slotVisitor;
+
+ WeakSet m_weakSet;
+ HandleSet m_handleSet;
HandleStack m_handleStack;
+ DFGCodeBlocks m_dfgCodeBlocks;
+ FinalizerOwner m_finalizerOwner;
+
+ bool m_isSafeToCollect;
- size_t m_extraCost;
+ JSGlobalData* m_globalData;
+ double m_lastGCLength;
+ double m_lastCodeDiscardTime;
+
+ DoublyLinkedList<FunctionExecutable> m_functions;
+
+ GCActivityCallback* m_activityCallback;
};
+ inline bool Heap::shouldCollect()
+ {
+#if ENABLE(GGC)
+ return m_objectSpace.nurseryWaterMark() >= m_minBytesPerCycle && m_isSafeToCollect && m_operationInProgress == NoOperation;
+#else
+ return m_bytesAllocated > m_bytesAllocatedLimit && m_isSafeToCollect && m_operationInProgress == NoOperation;
+#endif
+ }
+
bool Heap::isBusy()
{
return m_operationInProgress != NoOperation;
}
- inline bool Heap::isMarked(const JSCell* cell)
+ inline Heap* Heap::heap(const JSCell* cell)
{
- return MarkedSpace::isMarked(cell);
+ return MarkedBlock::blockFor(cell)->heap();
}
- inline bool Heap::testAndSetMarked(const JSCell* cell)
+ inline Heap* Heap::heap(const JSValue v)
{
- return MarkedSpace::testAndSetMarked(cell);
+ if (!v.isCell())
+ return 0;
+ return heap(v.asCell());
}
- inline void Heap::setMarked(JSCell* cell)
+ inline bool Heap::isMarked(const void* cell)
{
- MarkedSpace::setMarked(cell);
+ return MarkedBlock::blockFor(cell)->isMarked(cell);
}
- inline void Heap::writeBarrier(const JSCell*, JSValue)
+ inline bool Heap::testAndSetMarked(const void* cell)
+ {
+ return MarkedBlock::blockFor(cell)->testAndSetMarked(cell);
+ }
+
+ inline void Heap::setMarked(const void* cell)
+ {
+ MarkedBlock::blockFor(cell)->setMarked(cell);
+ }
+
+#if ENABLE(GGC)
+ inline uint8_t* Heap::addressOfCardFor(JSCell* cell)
{
+ return MarkedBlock::blockFor(cell)->addressOfCardFor(cell);
}
+ inline void Heap::writeBarrier(const JSCell* owner, JSCell*)
+ {
+ WriteBarrierCounters::countWriteBarrier();
+ MarkedBlock* block = MarkedBlock::blockFor(owner);
+ if (block->isMarked(owner))
+ block->setDirtyObject(owner);
+ }
+
+ inline void Heap::writeBarrier(const JSCell* owner, JSValue value)
+ {
+ if (!value)
+ return;
+ if (!value.isCell())
+ return;
+ writeBarrier(owner, value.asCell());
+ }
+#else
+
inline void Heap::writeBarrier(const JSCell*, JSCell*)
{
+ WriteBarrierCounters::countWriteBarrier();
}
- inline bool Heap::contains(void* p)
+ inline void Heap::writeBarrier(const JSCell*, JSValue)
{
- return m_markedSpace.contains(p);
+ WriteBarrierCounters::countWriteBarrier();
}
+#endif
inline void Heap::reportExtraMemoryCost(size_t cost)
{
reportExtraMemoryCostSlowCase(cost);
}
- template <typename Functor> inline void Heap::forEach(Functor& functor)
+ template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell(Functor& functor)
+ {
+ ProtectCountSet::iterator end = m_protectedValues.end();
+ for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it)
+ functor(it->first);
+ m_handleSet.forEachStrongHandle(functor, m_protectedValues);
+
+ return functor.returnValue();
+ }
+
+ template<typename Functor> inline typename Functor::ReturnType Heap::forEachProtectedCell()
+ {
+ Functor functor;
+ return forEachProtectedCell(functor);
+ }
+
+ inline void* Heap::allocateWithDestructor(size_t bytes)
+ {
+ ASSERT(isValidAllocation(bytes));
+ return m_objectSpace.allocateWithDestructor(bytes);
+ }
+
+ inline void* Heap::allocateWithoutDestructor(size_t bytes)
+ {
+ ASSERT(isValidAllocation(bytes));
+ return m_objectSpace.allocateWithoutDestructor(bytes);
+ }
+
+ inline CheckedBoolean Heap::tryAllocateStorage(size_t bytes, void** outPtr)
+ {
+ return m_storageSpace.tryAllocate(bytes, outPtr);
+ }
+
+ inline CheckedBoolean Heap::tryReallocateStorage(void** ptr, size_t oldSize, size_t newSize)
+ {
+ return m_storageSpace.tryReallocate(ptr, oldSize, newSize);
+ }
+
+ inline BlockAllocator& Heap::blockAllocator()
{
- m_markedSpace.forEach(functor);
+ return m_blockAllocator;
}
} // namespace JSC