diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime/Heap.cpp')
-rw-r--r-- | Source/JavaScriptCore/runtime/Heap.cpp | 222 |
1 files changed, 108 insertions, 114 deletions
diff --git a/Source/JavaScriptCore/runtime/Heap.cpp b/Source/JavaScriptCore/runtime/Heap.cpp index a224ee0..c05233c 100644 --- a/Source/JavaScriptCore/runtime/Heap.cpp +++ b/Source/JavaScriptCore/runtime/Heap.cpp @@ -21,7 +21,8 @@ #include "config.h" #include "Heap.h" -#include "CollectorHeapIterator.h" +#include "CodeBlock.h" +#include "ConservativeSet.h" #include "GCActivityCallback.h" #include "GCHandle.h" #include "Interpreter.h" @@ -30,18 +31,24 @@ #include "JSLock.h" #include "JSONObject.h" #include "Tracing.h" +#include <algorithm> #define COLLECT_ON_EVERY_ALLOCATION 0 +using namespace std; + namespace JSC { +const size_t minBytesPerCycle = 512 * 1024; + Heap::Heap(JSGlobalData* globalData) - : m_markedSpace(globalData) - , m_operationInProgress(NoOperation) + : m_operationInProgress(NoOperation) + , m_markedSpace(globalData) , m_markListSet(0) , m_activityCallback(DefaultGCActivityCallback::create(this)) , m_globalData(globalData) - , m_machineStackMarker(&globalData->heap) + , m_machineStackMarker(this) + , m_markStack(globalData->jsArrayVPtr) , m_extraCost(0) { (*m_activityCallback)(); @@ -70,14 +77,12 @@ void Heap::destroy() delete m_markListSet; m_markListSet = 0; - ProtectCountSet protectedValuesCopy = m_protectedValues; - m_markedSpace.destroy(protectedValuesCopy); - ASSERT(!protectedObjectCount()); + m_markedSpace.destroy(); m_globalData = 0; } -void Heap::recordExtraCost(size_t cost) +void Heap::reportExtraMemoryCostSlowCase(size_t cost) { // Our frequency of garbage collection tries to balance memory use against speed // by collecting based on the number of newly created values. However, for values @@ -90,26 +95,8 @@ void Heap::recordExtraCost(size_t cost) // if a large value survives one garbage collection, there is not much point to // collecting more frequently as long as it stays alive. - if (m_extraCost > maxExtraCost && m_extraCost > m_markedSpace.size() / 2) { - JAVASCRIPTCORE_GC_BEGIN(); - - // If the last iteration through the heap deallocated blocks, we need - // to clean up remaining garbage before marking. Otherwise, the conservative - // marking mechanism might follow a pointer to unmapped memory. - if (m_markedSpace.didShrink()) - m_markedSpace.sweep(); - - markRoots(); - - JAVASCRIPTCORE_GC_MARKED(); - - m_markedSpace.reset(); - m_extraCost = 0; - - JAVASCRIPTCORE_GC_END(); - - (*m_activityCallback)(); - } + if (m_extraCost > maxExtraCost && m_extraCost > m_markedSpace.capacity() / 2) + collectAllGarbage(); m_extraCost += cost; } @@ -118,7 +105,7 @@ void* Heap::allocate(size_t s) ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable()); ASSERT(JSLock::lockCount() > 0); ASSERT(JSLock::currentThreadIsHoldingLock()); - ASSERT_UNUSED(s, s <= HeapConstants::cellSize); + ASSERT_UNUSED(s, s <= MarkedBlock::CELL_SIZE); ASSERT(m_operationInProgress == NoOperation); #if COLLECT_ON_EVERY_ALLOCATION @@ -129,34 +116,18 @@ void* Heap::allocate(size_t s) m_operationInProgress = Allocation; void* result = m_markedSpace.allocate(s); m_operationInProgress = NoOperation; - if (!result) { - JAVASCRIPTCORE_GC_BEGIN(); - - markRoots(); - - JAVASCRIPTCORE_GC_MARKED(); - - m_markedSpace.reset(); - m_extraCost = 0; - - JAVASCRIPTCORE_GC_END(); - - (*m_activityCallback)(); + reset(DoNotSweep); m_operationInProgress = Allocation; result = m_markedSpace.allocate(s); m_operationInProgress = NoOperation; } + ASSERT(result); return result; } -void Heap::markConservatively(MarkStack& markStack, void* start, void* end) -{ - m_markedSpace.markConservatively(markStack, start, end); -} - void Heap::updateWeakGCHandles() { for (unsigned i = 0; i < m_weakGCHandlePools.size(); ++i) @@ -168,7 +139,7 @@ void WeakGCHandlePool::update() for (unsigned i = 1; i < WeakGCHandlePool::numPoolEntries; ++i) { if (m_entries[i].isValidPtr()) { JSCell* cell = m_entries[i].get(); - if (!cell || !Heap::isCellMarked(cell)) + if (!cell || !Heap::isMarked(cell)) m_entries[i].invalidate(); } } @@ -212,10 +183,8 @@ bool Heap::unprotect(JSValue k) void Heap::markProtectedObjects(MarkStack& markStack) { ProtectCountSet::iterator end = m_protectedValues.end(); - for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) { - markStack.append(it->first); - markStack.drain(); - } + for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) + markStack.deprecatedAppend(&it->first); } void Heap::pushTempSortVector(Vector<ValueStringPair>* tempVector) @@ -238,13 +207,18 @@ void Heap::markTempSortVectors(MarkStack& markStack) Vector<ValueStringPair>* tempSortingVector = *it; Vector<ValueStringPair>::iterator vectorEnd = tempSortingVector->end(); - for (Vector<ValueStringPair>::iterator vectorIt = tempSortingVector->begin(); vectorIt != vectorEnd; ++vectorIt) + for (Vector<ValueStringPair>::iterator vectorIt = tempSortingVector->begin(); vectorIt != vectorEnd; ++vectorIt) { if (vectorIt->first) - markStack.append(vectorIt->first); - markStack.drain(); + markStack.deprecatedAppend(&vectorIt->first); + } } } - + +inline RegisterFile& Heap::registerFile() +{ + return m_globalData->interpreter->registerFile(); +} + void Heap::markRoots() { #ifndef NDEBUG @@ -260,28 +234,40 @@ void Heap::markRoots() m_operationInProgress = Collection; - MarkStack& markStack = m_globalData->markStack; + // We gather the conservative set before clearing mark bits, because + // conservative gathering uses the mark bits from our last mark pass to + // determine whether a reference is valid. + ConservativeSet conservativeSet(this); + m_machineStackMarker.markMachineStackConservatively(conservativeSet); + conservativeSet.add(registerFile().start(), registerFile().end()); - // Reset mark bits. - m_markedSpace.clearMarkBits(); + m_markedSpace.clearMarks(); - // Mark stack roots. - m_machineStackMarker.markMachineStackConservatively(markStack); - m_globalData->interpreter->registerFile().markCallFrames(markStack, this); + MarkStack& markStack = m_markStack; + conservativeSet.mark(markStack); + markStack.drain(); // Mark explicitly registered roots. markProtectedObjects(markStack); + markStack.drain(); // Mark temporary vector for Array sorting markTempSortVectors(markStack); + markStack.drain(); + + HashSet<GlobalCodeBlock*>::const_iterator end = m_codeBlocks.end(); + for (HashSet<GlobalCodeBlock*>::const_iterator it = m_codeBlocks.begin(); it != end; ++it) + (*it)->markAggregate(markStack); + markStack.drain(); // Mark misc. other roots. if (m_markListSet && m_markListSet->size()) MarkedArgumentBuffer::markLists(markStack, *m_markListSet); if (m_globalData->exception) - markStack.append(m_globalData->exception); + markStack.append(&m_globalData->exception); if (m_globalData->firstStringifierToMark) JSONObject::markStringifiers(markStack, m_globalData->firstStringifierToMark); + markStack.drain(); // Mark the small strings cache last, since it will clear itself if nothing // else has marked it. @@ -300,39 +286,30 @@ size_t Heap::objectCount() const return m_markedSpace.objectCount(); } -MarkedSpace::Statistics Heap::statistics() const +size_t Heap::size() const { - return m_markedSpace.statistics(); + return m_markedSpace.size(); } -size_t Heap::size() const +size_t Heap::capacity() const { - return m_markedSpace.size(); + return m_markedSpace.capacity(); } size_t Heap::globalObjectCount() { - size_t count = 0; - if (JSGlobalObject* head = m_globalData->head) { - JSGlobalObject* o = head; - do { - ++count; - o = o->next(); - } while (o != head); - } - return count; + return m_globalData->globalObjects.uncheckedSize(); } size_t Heap::protectedGlobalObjectCount() { size_t count = 0; - if (JSGlobalObject* head = m_globalData->head) { - JSGlobalObject* o = head; - do { - if (m_protectedValues.contains(o)) - ++count; - o = o->next(); - } while (o != head); + + GlobalObjectMap& map = m_globalData->globalObjects; + GlobalObjectMap::iterator end = map.uncheckedEnd(); + for (GlobalObjectMap::iterator it = map.uncheckedBegin(); it != end; ++it) { + if (map.isValid(it) && m_protectedValues.contains(it->second.get())) + ++count; } return count; @@ -343,7 +320,23 @@ size_t Heap::protectedObjectCount() return m_protectedValues.size(); } -static const char* typeName(JSCell* cell) +class TypeCounter { +public: + TypeCounter(); + void operator()(JSCell*); + PassOwnPtr<TypeCountSet> take(); + +private: + const char* typeName(JSCell*); + OwnPtr<TypeCountSet> m_typeCountSet; +}; + +inline TypeCounter::TypeCounter() + : m_typeCountSet(new TypeCountSet) +{ +} + +inline const char* TypeCounter::typeName(JSCell* cell) { if (cell->isString()) return "string"; @@ -359,27 +352,32 @@ static const char* typeName(JSCell* cell) return info ? info->className : "Object"; } -HashCountedSet<const char*>* Heap::protectedObjectTypeCounts() +inline void TypeCounter::operator()(JSCell* cell) +{ + m_typeCountSet->add(typeName(cell)); +} + +inline PassOwnPtr<TypeCountSet> TypeCounter::take() +{ + return m_typeCountSet.release(); +} + +PassOwnPtr<TypeCountSet> Heap::protectedObjectTypeCounts() { - HashCountedSet<const char*>* counts = new HashCountedSet<const char*>; + TypeCounter typeCounter; ProtectCountSet::iterator end = m_protectedValues.end(); for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) - counts->add(typeName(it->first)); + typeCounter(it->first); - return counts; + return typeCounter.take(); } -HashCountedSet<const char*>* Heap::objectTypeCounts() +PassOwnPtr<TypeCountSet> Heap::objectTypeCounts() { - HashCountedSet<const char*>* counts = new HashCountedSet<const char*>; - - LiveObjectIterator it = primaryHeapBegin(); - LiveObjectIterator heapEnd = primaryHeapEnd(); - for ( ; it != heapEnd; ++it) - counts->add(typeName(*it)); - - return counts; + TypeCounter typeCounter; + forEach(typeCounter); + return typeCounter.take(); } bool Heap::isBusy() @@ -389,36 +387,32 @@ bool Heap::isBusy() void Heap::collectAllGarbage() { + reset(DoSweep); +} + +void Heap::reset(SweepToggle sweepToggle) +{ ASSERT(globalData()->identifierTable == wtfThreadData().currentIdentifierTable()); JAVASCRIPTCORE_GC_BEGIN(); - // If the last iteration through the heap deallocated blocks, we need - // to clean up remaining garbage before marking. Otherwise, the conservative - // marking mechanism might follow a pointer to unmapped memory. - if (m_markedSpace.didShrink()) - m_markedSpace.sweep(); - markRoots(); JAVASCRIPTCORE_GC_MARKED(); m_markedSpace.reset(); - m_markedSpace.sweep(); m_extraCost = 0; - JAVASCRIPTCORE_GC_END(); + if (sweepToggle == DoSweep) { + m_markedSpace.sweep(); + m_markedSpace.shrink(); + } - (*m_activityCallback)(); -} + size_t proportionalBytes = static_cast<size_t>(1.5 * m_markedSpace.size()); + m_markedSpace.setHighWaterMark(max(proportionalBytes, minBytesPerCycle)); -LiveObjectIterator Heap::primaryHeapBegin() -{ - return m_markedSpace.primaryHeapBegin(); -} + JAVASCRIPTCORE_GC_END(); -LiveObjectIterator Heap::primaryHeapEnd() -{ - return m_markedSpace.primaryHeapEnd(); + (*m_activityCallback)(); } void Heap::setActivityCallback(PassOwnPtr<GCActivityCallback> activityCallback) |