diff options
Diffstat (limited to 'Source/JavaScriptCore/heap')
-rw-r--r-- | Source/JavaScriptCore/heap/BlockAllocator.cpp | 6 | ||||
-rw-r--r-- | Source/JavaScriptCore/heap/BlockAllocator.h | 2 | ||||
-rw-r--r-- | Source/JavaScriptCore/heap/Heap.cpp | 152 | ||||
-rw-r--r-- | Source/JavaScriptCore/heap/Heap.h | 11 | ||||
-rw-r--r-- | Source/JavaScriptCore/heap/MachineStackMarker.cpp | 15 | ||||
-rw-r--r-- | Source/JavaScriptCore/heap/MarkStack.cpp | 78 | ||||
-rw-r--r-- | Source/JavaScriptCore/heap/MarkStack.h | 19 | ||||
-rw-r--r-- | Source/JavaScriptCore/heap/MarkedBlock.h | 12 | ||||
-rw-r--r-- | Source/JavaScriptCore/heap/MarkedSpace.h | 52 |
9 files changed, 143 insertions, 204 deletions
diff --git a/Source/JavaScriptCore/heap/BlockAllocator.cpp b/Source/JavaScriptCore/heap/BlockAllocator.cpp index 028c84c2d..ce6024079 100644 --- a/Source/JavaScriptCore/heap/BlockAllocator.cpp +++ b/Source/JavaScriptCore/heap/BlockAllocator.cpp @@ -33,6 +33,7 @@ namespace JSC { BlockAllocator::BlockAllocator() : m_numberOfFreeBlocks(0) + , m_isCurrentlyAllocating(false) , m_blockFreeingThreadShouldQuit(false) , m_blockFreeingThread(createThread(blockFreeingThreadStartFunc, this, "JavaScriptCore::BlockFree")) { @@ -104,6 +105,11 @@ void BlockAllocator::blockFreeingThreadMain() if (m_blockFreeingThreadShouldQuit) break; + if (m_isCurrentlyAllocating) { + m_isCurrentlyAllocating = false; + continue; + } + // Now process the list of free blocks. Keep freeing until half of the // blocks that are currently on the list are gone. Assume that a size_t // field can be accessed atomically. diff --git a/Source/JavaScriptCore/heap/BlockAllocator.h b/Source/JavaScriptCore/heap/BlockAllocator.h index 4b90d28b9..cc9557f85 100644 --- a/Source/JavaScriptCore/heap/BlockAllocator.h +++ b/Source/JavaScriptCore/heap/BlockAllocator.h @@ -56,6 +56,7 @@ private: DoublyLinkedList<HeapBlock> m_freeBlocks; size_t m_numberOfFreeBlocks; + bool m_isCurrentlyAllocating; bool m_blockFreeingThreadShouldQuit; Mutex m_freeBlockLock; ThreadCondition m_freeBlockCondition; @@ -65,6 +66,7 @@ private: inline HeapBlock* BlockAllocator::allocate() { MutexLocker locker(m_freeBlockLock); + m_isCurrentlyAllocating = true; if (!m_numberOfFreeBlocks) { ASSERT(m_freeBlocks.isEmpty()); return 0; diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp index d43ec1242..2254b5b01 100644 --- a/Source/JavaScriptCore/heap/Heap.cpp +++ b/Source/JavaScriptCore/heap/Heap.cpp @@ -178,100 +178,20 @@ static inline bool isValidThreadState(JSGlobalData* globalData) return true; } -class CountFunctor { -public: - typedef size_t ReturnType; - - CountFunctor(); - void count(size_t); - ReturnType returnValue(); - -private: - ReturnType m_count; -}; - -inline CountFunctor::CountFunctor() - : m_count(0) -{ -} - -inline void CountFunctor::count(size_t count) -{ - m_count += count; -} - -inline CountFunctor::ReturnType CountFunctor::returnValue() -{ - return m_count; -} - -struct ClearMarks : MarkedBlock::VoidFunctor { - void operator()(MarkedBlock*); -}; - -inline void ClearMarks::operator()(MarkedBlock* block) -{ - block->clearMarks(); -} - -struct Sweep : MarkedBlock::VoidFunctor { - void operator()(MarkedBlock*); -}; - -inline void Sweep::operator()(MarkedBlock* block) -{ - block->sweep(); -} - -struct MarkCount : CountFunctor { - void operator()(MarkedBlock*); -}; - -inline void MarkCount::operator()(MarkedBlock* block) -{ - count(block->markCount()); -} - -struct Size : CountFunctor { - void operator()(MarkedBlock*); -}; - -inline void Size::operator()(MarkedBlock* block) -{ - count(block->markCount() * block->cellSize()); -} - -struct Capacity : CountFunctor { - void operator()(MarkedBlock*); +struct Count : public MarkedBlock::CountFunctor { + void operator()(JSCell*) { count(1); } }; -inline void Capacity::operator()(MarkedBlock* block) -{ - count(block->capacity()); -} - -struct Count : public CountFunctor { - void operator()(JSCell*); -}; - -inline void Count::operator()(JSCell*) -{ - count(1); -} - -struct CountIfGlobalObject : CountFunctor { - void operator()(JSCell*); +struct CountIfGlobalObject : MarkedBlock::CountFunctor { + void operator()(JSCell* cell) { + if (!cell->isObject()) + return; + if (!asObject(cell)->isGlobalObject()) + return; + count(1); + } }; -inline void CountIfGlobalObject::operator()(JSCell* cell) -{ - if (!cell->isObject()) - return; - if (!asObject(cell)->isGlobalObject()) - return; - count(1); -} - class RecordType { public: typedef PassOwnPtr<TypeCountSet> ReturnType; @@ -363,9 +283,9 @@ void Heap::lastChanceToFinalize() WTFLogAlways("ERROR: JavaScriptCore heap deallocated while %ld values were still protected", static_cast<unsigned long>(size)); m_weakSet.finalizeAll(); - canonicalizeCellLivenessData(); - clearMarks(); - sweep(); + m_objectSpace.canonicalizeCellLivenessData(); + m_objectSpace.clearMarks(); + m_objectSpace.sweep(); m_globalData->smallStrings.finalizeSmallStrings(); #if ENABLE(SIMPLE_HEAP_PROFILING) @@ -540,7 +460,7 @@ void Heap::markRoots(bool fullGC) #endif { GCPHASE(clearMarks); - clearMarks(); + m_objectSpace.clearMarks(); } m_storageSpace.startedCopying(); @@ -656,37 +576,24 @@ void Heap::markRoots(bool fullGC) visitor.doneCopying(); visitor.reset(); m_sharedData.reset(); -#if ENABLE(PARALLEL_GC) - m_sharedData.resetChildren(); -#endif m_storageSpace.doneCopying(); m_operationInProgress = NoOperation; } -void Heap::clearMarks() -{ - m_objectSpace.forEachBlock<ClearMarks>(); -} - -void Heap::sweep() -{ - m_objectSpace.forEachBlock<Sweep>(); -} - size_t Heap::objectCount() { - return m_objectSpace.forEachBlock<MarkCount>(); + return m_objectSpace.objectCount(); } size_t Heap::size() { - return m_objectSpace.forEachBlock<Size>() + m_storageSpace.size(); + return m_objectSpace.size() + m_storageSpace.size(); } size_t Heap::capacity() { - return m_objectSpace.forEachBlock<Capacity>() + m_storageSpace.capacity(); + return m_objectSpace.capacity() + m_storageSpace.capacity(); } size_t Heap::protectedGlobalObjectCount() @@ -761,7 +668,7 @@ void Heap::collect(SweepToggle sweepToggle) #endif { GCPHASE(Canonicalize); - canonicalizeCellLivenessData(); + m_objectSpace.canonicalizeCellLivenessData(); } markRoots(fullGC); @@ -780,8 +687,9 @@ void Heap::collect(SweepToggle sweepToggle) JAVASCRIPTCORE_GC_MARKED(); { - GCPHASE(ResetAllocator); - resetAllocators(); + GCPHASE(ResetAllocators); + m_objectSpace.resetAllocators(); + m_weakSet.resetAllocator(); } { @@ -792,7 +700,7 @@ void Heap::collect(SweepToggle sweepToggle) if (sweepToggle == DoSweep) { SamplingRegion samplingRegion("Garbage Collection: Sweeping"); GCPHASE(Sweeping); - sweep(); + m_objectSpace.sweep(); m_objectSpace.shrink(); m_weakSet.shrink(); m_bytesAbandoned = 0; @@ -814,17 +722,6 @@ void Heap::collect(SweepToggle sweepToggle) JAVASCRIPTCORE_GC_END(); } -void Heap::canonicalizeCellLivenessData() -{ - m_objectSpace.canonicalizeCellLivenessData(); -} - -void Heap::resetAllocators() -{ - m_objectSpace.resetAllocators(); - m_weakSet.resetAllocator(); -} - void Heap::setActivityCallback(PassOwnPtr<GCActivityCallback> activityCallback) { m_activityCallback = activityCallback; @@ -835,6 +732,11 @@ GCActivityCallback* Heap::activityCallback() return m_activityCallback.get(); } +void Heap::setGarbageCollectionTimerEnabled(bool enable) +{ + activityCallback()->setEnabled(enable); +} + void Heap::didAllocate(size_t bytes) { m_activityCallback->didAllocate(m_bytesAllocated + m_bytesAbandoned); diff --git a/Source/JavaScriptCore/heap/Heap.h b/Source/JavaScriptCore/heap/Heap.h index 10fdb07be..6bf82e4a5 100644 --- a/Source/JavaScriptCore/heap/Heap.h +++ b/Source/JavaScriptCore/heap/Heap.h @@ -100,6 +100,7 @@ namespace JSC { JS_EXPORT_PRIVATE GCActivityCallback* activityCallback(); JS_EXPORT_PRIVATE void setActivityCallback(PassOwnPtr<GCActivityCallback>); + JS_EXPORT_PRIVATE void setGarbageCollectionTimerEnabled(bool); // true if an allocation or collection is in progress inline bool isBusy(); @@ -187,22 +188,12 @@ namespace JSC { 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 resetAllocators(); - - void clearMarks(); void markRoots(bool fullGC); void markProtectedObjects(HeapRootVisitor&); void markTempSortVectors(HeapRootVisitor&); void harvestWeakReferences(); void finalizeUnconditionalFinalizers(); - void sweep(); - RegisterFile& registerFile(); BlockAllocator& blockAllocator(); diff --git a/Source/JavaScriptCore/heap/MachineStackMarker.cpp b/Source/JavaScriptCore/heap/MachineStackMarker.cpp index 30915eaf8..affd833eb 100644 --- a/Source/JavaScriptCore/heap/MachineStackMarker.cpp +++ b/Source/JavaScriptCore/heap/MachineStackMarker.cpp @@ -452,8 +452,6 @@ static void freePlatformThreadRegisters(PlatformThreadRegisters& regs) void MachineThreads::gatherFromOtherThread(ConservativeRoots& conservativeRoots, Thread* thread) { - suspendThread(thread->platformThread); - PlatformThreadRegisters regs; size_t regSize = getPlatformThreadRegisters(thread->platformThread, regs); @@ -464,8 +462,6 @@ void MachineThreads::gatherFromOtherThread(ConservativeRoots& conservativeRoots, swapIfBackwards(stackPointer, stackBase); conservativeRoots.add(stackPointer, stackBase); - resumeThread(thread->platformThread); - freePlatformThreadRegisters(regs); } @@ -484,12 +480,23 @@ void MachineThreads::gatherConservativeRoots(ConservativeRoots& conservativeRoot // thread that had been suspended while holding the malloc lock. fastMallocForbid(); #endif + for (Thread* thread = m_registeredThreads; thread; thread = thread->next) { + if (!equalThread(thread->platformThread, currentPlatformThread)) + suspendThread(thread->platformThread); + } + // It is safe to access the registeredThreads list, because we earlier asserted that locks are being held, // and since this is a shared heap, they are real locks. for (Thread* thread = m_registeredThreads; thread; thread = thread->next) { if (!equalThread(thread->platformThread, currentPlatformThread)) gatherFromOtherThread(conservativeRoots, thread); } + + for (Thread* thread = m_registeredThreads; thread; thread = thread->next) { + if (!equalThread(thread->platformThread, currentPlatformThread)) + resumeThread(thread->platformThread); + } + #ifndef NDEBUG fastMallocAllow(); #endif diff --git a/Source/JavaScriptCore/heap/MarkStack.cpp b/Source/JavaScriptCore/heap/MarkStack.cpp index 785444e55..678f1cb45 100644 --- a/Source/JavaScriptCore/heap/MarkStack.cpp +++ b/Source/JavaScriptCore/heap/MarkStack.cpp @@ -36,8 +36,8 @@ #include "JSObject.h" #include "ScopeChain.h" #include "Structure.h" -#include "UString.h" #include "WriteBarrier.h" +#include <wtf/DataLog.h> #include <wtf/MainThread.h> namespace JSC { @@ -219,24 +219,19 @@ void MarkStackArray::stealSomeCellsFrom(MarkStackArray& other) } #if ENABLE(PARALLEL_GC) -void MarkStackThreadSharedData::resetChildren() -{ - for (unsigned i = 0; i < m_slaveMarkStacks.size(); ++i) - m_slaveMarkStacks[i]->reset(); -} - -void MarkStackThreadSharedData::markingThreadMain(SlotVisitor* slotVisitor) +void MarkStackThreadSharedData::markingThreadMain() { WTF::registerGCThread(); - ParallelModeEnabler enabler(*slotVisitor); - slotVisitor->drainFromShared(SlotVisitor::SlaveDrain); - delete slotVisitor; + { + SlotVisitor slotVisitor(*this); + ParallelModeEnabler enabler(slotVisitor); + slotVisitor.drainFromShared(SlotVisitor::SlaveDrain); + } } -void MarkStackThreadSharedData::markingThreadStartFunc(void* myVisitor) +void MarkStackThreadSharedData::markingThreadStartFunc(void* shared) { - SlotVisitor* slotVisitor = static_cast<SlotVisitor*>(myVisitor); - slotVisitor->sharedData().markingThreadMain(slotVisitor); + static_cast<MarkStackThreadSharedData*>(shared)->markingThreadMain(); } #endif @@ -249,9 +244,7 @@ MarkStackThreadSharedData::MarkStackThreadSharedData(JSGlobalData* globalData) { #if ENABLE(PARALLEL_GC) for (unsigned i = 1; i < Options::numberOfGCMarkers; ++i) { - SlotVisitor* slotVisitor = new SlotVisitor(*this); - m_slaveMarkStacks.append(slotVisitor); - m_markingThreads.append(createThread(markingThreadStartFunc, slotVisitor, "JavaScriptCore::Marking")); + m_markingThreads.append(createThread(markingThreadStartFunc, this, "JavaScriptCore::Marking")); ASSERT(m_markingThreads.last()); } #endif @@ -283,6 +276,7 @@ void MarkStackThreadSharedData::reset() #else ASSERT(m_opaqueRoots.isEmpty()); #endif + m_weakReferenceHarvesters.removeAll(); } @@ -295,7 +289,6 @@ void MarkStack::reset() #else m_opaqueRoots.clear(); #endif - m_uniqueStrings.clear(); } void MarkStack::append(ConservativeRoots& conservativeRoots) @@ -496,34 +489,6 @@ void* SlotVisitor::allocateNewSpace(void* ptr, size_t bytes) return CopiedSpace::allocateFromBlock(m_copyBlock, bytes); } -inline void MarkStack::internalAppend(JSValue* slot) -{ - ASSERT(slot); - JSValue value = *slot; - ASSERT(value); - if (!value.isCell()) - return; - - if (value.isString()) { - JSString* string = jsCast<JSString*>(value.asCell()); - if (!string->isHashConstSingleton() && string->length() > 1 && !string->isRope()) { - UniqueStringMap::AddResult addResult = m_uniqueStrings.add(string->string().impl(), value); - if (addResult.isNewEntry) - string->setHashConstSingleton(); - else { - JSValue existingJSValue = addResult.iterator->second; - if (value != existingJSValue) - jsCast<JSString*>(existingJSValue.asCell())->clearHashConstSingleton(); - *slot = existingJSValue; - return; - } - } - } - - internalAppend(value.asCell()); -} - - void SlotVisitor::copyAndAppend(void** ptr, size_t bytes, JSValue* values, unsigned length) { void* oldPtr = *ptr; @@ -537,7 +502,7 @@ void SlotVisitor::copyAndAppend(void** ptr, size_t bytes, JSValue* values, unsig newValues[i] = value; if (!value) continue; - internalAppend(&newValues[i]); + internalAppend(value); } memcpy(newPtr, oldPtr, jsValuesOffset); @@ -571,16 +536,29 @@ void SlotVisitor::finalizeUnconditionalFinalizers() #if ENABLE(GC_VALIDATION) void MarkStack::validate(JSCell* cell) { - if (!cell) + if (!cell) { + dataLog("cell is NULL\n"); CRASH(); + } - if (!cell->structure()) + if (!cell->structure()) { + dataLog("cell at %p has a null structure\n" , cell); CRASH(); + } // Both the cell's structure, and the cell's structure's structure should be the Structure Structure. // I hate this sentence. - if (cell->structure()->structure()->JSCell::classInfo() != cell->structure()->JSCell::classInfo()) + if (cell->structure()->structure()->JSCell::classInfo() != cell->structure()->JSCell::classInfo()) { + const char* parentClassName = 0; + const char* ourClassName = 0; + if (cell->structure()->structure() && cell->structure()->structure()->JSCell::classInfo()) + parentClassName = cell->structure()->structure()->JSCell::classInfo()->className; + if (cell->structure()->JSCell::classInfo()) + ourClassName = cell->structure()->JSCell::classInfo()->className; + dataLog("parent structure (%p <%s>) of cell at %p doesn't match cell's structure (%p <%s>)\n", + cell->structure()->structure(), parentClassName, cell, cell->structure(), ourClassName); CRASH(); + } } #else void MarkStack::validate(JSCell*) diff --git a/Source/JavaScriptCore/heap/MarkStack.h b/Source/JavaScriptCore/heap/MarkStack.h index 48b65c069..0695b1b32 100644 --- a/Source/JavaScriptCore/heap/MarkStack.h +++ b/Source/JavaScriptCore/heap/MarkStack.h @@ -34,14 +34,12 @@ #include "UnconditionalFinalizer.h" #include "VTableSpectrum.h" #include "WeakReferenceHarvester.h" -#include <wtf/Forward.h> #include <wtf/HashMap.h> #include <wtf/HashSet.h> #include <wtf/Vector.h> #include <wtf/Noncopyable.h> #include <wtf/OSAllocator.h> #include <wtf/PageBlock.h> -#include <wtf/text/StringHash.h> namespace JSC { @@ -173,17 +171,13 @@ namespace JSC { ~MarkStackThreadSharedData(); void reset(); - -#if ENABLE(PARALLEL_GC) - void resetChildren(); -#endif - + private: friend class MarkStack; friend class SlotVisitor; #if ENABLE(PARALLEL_GC) - void markingThreadMain(SlotVisitor*); + void markingThreadMain(); static void markingThreadStartFunc(void* heap); #endif @@ -193,7 +187,6 @@ namespace JSC { MarkStackSegmentAllocator m_segmentAllocator; Vector<ThreadIdentifier> m_markingThreads; - Vector<MarkStack*> m_slaveMarkStacks; Mutex m_markingLock; ThreadCondition m_markingCondition; @@ -228,14 +221,13 @@ namespace JSC { void addOpaqueRoot(void*); bool containsOpaqueRoot(void*); int opaqueRootCount(); - - MarkStackThreadSharedData& sharedData() { return m_shared; } + bool isEmpty() { return m_stack.isEmpty(); } void reset(); size_t visitCount() const { return m_visitCount; } - + #if ENABLE(SIMPLE_HEAP_PROFILING) VTableSpectrum m_visitedTypeCounts; #endif @@ -259,7 +251,6 @@ namespace JSC { void internalAppend(JSCell*); void internalAppend(JSValue); - void internalAppend(JSValue*); JS_EXPORT_PRIVATE void mergeOpaqueRoots(); @@ -279,8 +270,6 @@ namespace JSC { MarkStackArray m_stack; HashSet<void*> m_opaqueRoots; // Handle-owning data structures not visible to the garbage collector. - typedef HashMap<StringImpl*, JSValue> UniqueStringMap; - UniqueStringMap m_uniqueStrings; #if !ASSERT_DISABLED public: diff --git a/Source/JavaScriptCore/heap/MarkedBlock.h b/Source/JavaScriptCore/heap/MarkedBlock.h index 429b7c08e..aa99ebf48 100644 --- a/Source/JavaScriptCore/heap/MarkedBlock.h +++ b/Source/JavaScriptCore/heap/MarkedBlock.h @@ -100,6 +100,18 @@ namespace JSC { void returnValue() { } }; + class CountFunctor { + public: + typedef size_t ReturnType; + + CountFunctor() : m_count(0) { } + void count(size_t count) { m_count += count; } + ReturnType returnValue() { return m_count; } + + private: + ReturnType m_count; + }; + static MarkedBlock* create(Heap*, size_t cellSize, bool cellsNeedDestruction); static MarkedBlock* recycle(MarkedBlock*, Heap*, size_t cellSize, bool cellsNeedDestruction); static void destroy(MarkedBlock*); diff --git a/Source/JavaScriptCore/heap/MarkedSpace.h b/Source/JavaScriptCore/heap/MarkedSpace.h index 19061a12b..7bd5ca509 100644 --- a/Source/JavaScriptCore/heap/MarkedSpace.h +++ b/Source/JavaScriptCore/heap/MarkedSpace.h @@ -45,6 +45,26 @@ class LLIntOffsetsExtractor; class WeakGCHandle; class SlotVisitor; +struct ClearMarks : MarkedBlock::VoidFunctor { + void operator()(MarkedBlock* block) { block->clearMarks(); } +}; + +struct Sweep : MarkedBlock::VoidFunctor { + void operator()(MarkedBlock* block) { block->sweep(); } +}; + +struct MarkCount : MarkedBlock::CountFunctor { + void operator()(MarkedBlock* block) { count(block->markCount()); } +}; + +struct Size : MarkedBlock::CountFunctor { + void operator()(MarkedBlock* block) { count(block->markCount() * block->cellSize()); } +}; + +struct Capacity : MarkedBlock::CountFunctor { + void operator()(MarkedBlock* block) { count(block->capacity()); } +}; + class MarkedSpace { WTF_MAKE_NONCOPYABLE(MarkedSpace); public: @@ -73,11 +93,18 @@ public: template<typename Functor> typename Functor::ReturnType forEachBlock(); void shrink(); + void freeAllBlocks(); void freeBlocks(MarkedBlock* head); void didAddBlock(MarkedBlock*); void didConsumeFreeList(MarkedBlock*); + void clearMarks(); + void sweep(); + size_t objectCount(); + size_t size(); + size_t capacity(); + bool isPagedOut(double deadline); private: @@ -185,6 +212,31 @@ inline void MarkedSpace::didAddBlock(MarkedBlock* block) m_blocks.add(block); } +inline void MarkedSpace::clearMarks() +{ + forEachBlock<ClearMarks>(); +} + +inline void MarkedSpace::sweep() +{ + forEachBlock<Sweep>(); +} + +inline size_t MarkedSpace::objectCount() +{ + return forEachBlock<MarkCount>(); +} + +inline size_t MarkedSpace::size() +{ + return forEachBlock<Size>(); +} + +inline size_t MarkedSpace::capacity() +{ + return forEachBlock<Capacity>(); +} + } // namespace JSC #endif // MarkedSpace_h |