diff options
Diffstat (limited to 'Source/JavaScriptCore/heap')
-rw-r--r-- | Source/JavaScriptCore/heap/CopiedSpace.cpp | 49 | ||||
-rw-r--r-- | Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h | 1 | ||||
-rw-r--r-- | Source/JavaScriptCore/heap/CopyVisitorInlineMethods.h | 4 | ||||
-rw-r--r-- | Source/JavaScriptCore/heap/GCThread.cpp | 10 | ||||
-rw-r--r-- | Source/JavaScriptCore/heap/GCThreadSharedData.cpp | 57 | ||||
-rw-r--r-- | Source/JavaScriptCore/heap/GCThreadSharedData.h | 5 | ||||
-rw-r--r-- | Source/JavaScriptCore/heap/Heap.cpp | 7 | ||||
-rw-r--r-- | Source/JavaScriptCore/heap/SlotVisitor.cpp | 10 |
8 files changed, 93 insertions, 50 deletions
diff --git a/Source/JavaScriptCore/heap/CopiedSpace.cpp b/Source/JavaScriptCore/heap/CopiedSpace.cpp index cedafee3a..c228f9460 100644 --- a/Source/JavaScriptCore/heap/CopiedSpace.cpp +++ b/Source/JavaScriptCore/heap/CopiedSpace.cpp @@ -173,6 +173,7 @@ void CopiedSpace::doneFillingBlock(CopiedBlock* block, CopiedBlock** exchange) { MutexLocker locker(m_loanedBlocksLock); ASSERT(m_numberOfLoanedBlocks > 0); + ASSERT(m_inCopyingPhase); m_numberOfLoanedBlocks--; if (!m_numberOfLoanedBlocks) m_loanedBlocksCondition.signal(); @@ -199,6 +200,22 @@ void CopiedSpace::startedCopying() totalUsableBytes += block->payloadCapacity(); } + CopiedBlock* block = m_oversizeBlocks.head(); + while (block) { + CopiedBlock* next = block->next(); + if (block->isPinned()) { + m_blockFilter.add(reinterpret_cast<Bits>(block)); + totalLiveBytes += block->payloadCapacity(); + totalUsableBytes += block->payloadCapacity(); + block->didSurviveGC(); + } else { + m_oversizeBlocks.remove(block); + m_blockSet.remove(block); + m_heap->blockAllocator().deallocateCustomSize(CopiedBlock::destroy(block)); + } + block = next; + } + double markedSpaceBytes = m_heap->objectSpace().capacity(); double totalFragmentation = ((double)totalLiveBytes + markedSpaceBytes) / ((double)totalUsableBytes + markedSpaceBytes); m_shouldDoCopyPhase = totalFragmentation <= Options::minHeapUtilization(); @@ -224,31 +241,13 @@ void CopiedSpace::doneCopying() while (!m_fromSpace->isEmpty()) { CopiedBlock* block = m_fromSpace->removeHead(); - if (block->isPinned() || !m_shouldDoCopyPhase) { - block->didSurviveGC(); - // We don't add the block to the blockSet because it was never removed. - ASSERT(m_blockSet.contains(block)); - m_blockFilter.add(reinterpret_cast<Bits>(block)); - m_toSpace->push(block); - continue; - } - - m_blockSet.remove(block); - m_heap->blockAllocator().deallocate(CopiedBlock::destroy(block)); - } - - CopiedBlock* curr = m_oversizeBlocks.head(); - while (curr) { - CopiedBlock* next = curr->next(); - if (!curr->isPinned()) { - m_oversizeBlocks.remove(curr); - m_blockSet.remove(curr); - m_heap->blockAllocator().deallocateCustomSize(CopiedBlock::destroy(curr)); - } else { - m_blockFilter.add(reinterpret_cast<Bits>(curr)); - curr->didSurviveGC(); - } - curr = next; + // All non-pinned blocks in from-space should have been reclaimed as they were evacuated. + ASSERT(block->isPinned() || !m_shouldDoCopyPhase); + block->didSurviveGC(); + // We don't add the block to the blockSet because it was never removed. + ASSERT(m_blockSet.contains(block)); + m_blockFilter.add(reinterpret_cast<Bits>(block)); + m_toSpace->push(block); } if (!m_toSpace->head()) diff --git a/Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h b/Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h index 01e816793..c244015e7 100644 --- a/Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h +++ b/Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h @@ -113,6 +113,7 @@ inline void CopiedSpace::recycleBorrowedBlock(CopiedBlock* block) { MutexLocker locker(m_loanedBlocksLock); ASSERT(m_numberOfLoanedBlocks > 0); + ASSERT(m_inCopyingPhase); m_numberOfLoanedBlocks--; if (!m_numberOfLoanedBlocks) m_loanedBlocksCondition.signal(); diff --git a/Source/JavaScriptCore/heap/CopyVisitorInlineMethods.h b/Source/JavaScriptCore/heap/CopyVisitorInlineMethods.h index 73400750f..eb7bd2e82 100644 --- a/Source/JavaScriptCore/heap/CopyVisitorInlineMethods.h +++ b/Source/JavaScriptCore/heap/CopyVisitorInlineMethods.h @@ -56,10 +56,8 @@ private: inline bool CopyVisitor::checkIfShouldCopy(void* oldPtr, size_t bytes) { - if (CopiedSpace::isOversize(bytes)) { - ASSERT(CopiedSpace::oversizeBlockFor(oldPtr)->isPinned()); + if (CopiedSpace::isOversize(bytes)) return false; - } if (CopiedSpace::blockFor(oldPtr)->isPinned()) return false; diff --git a/Source/JavaScriptCore/heap/GCThread.cpp b/Source/JavaScriptCore/heap/GCThread.cpp index ea43456bd..ce3bbedc9 100644 --- a/Source/JavaScriptCore/heap/GCThread.cpp +++ b/Source/JavaScriptCore/heap/GCThread.cpp @@ -70,8 +70,16 @@ CopyVisitor* GCThread::copyVisitor() GCPhase GCThread::waitForNextPhase() { MutexLocker locker(m_shared.m_phaseLock); + while (m_shared.m_gcThreadsShouldWait) + m_shared.m_phaseCondition.wait(m_shared.m_phaseLock); + + m_shared.m_numberOfActiveGCThreads--; + if (!m_shared.m_numberOfActiveGCThreads) + m_shared.m_activityCondition.signal(); + while (m_shared.m_currentPhase == NoPhase) m_shared.m_phaseCondition.wait(m_shared.m_phaseLock); + m_shared.m_numberOfActiveGCThreads++; return m_shared.m_currentPhase; } @@ -84,7 +92,7 @@ void GCThread::gcThreadMain() // Wait for the main thread to finish creating and initializing us. The main thread grabs this lock before // creating this thread. We aren't guaranteed to have a valid threadID until the main thread releases this lock. { - MutexLocker locker(m_shared.m_markingLock); + MutexLocker locker(m_shared.m_phaseLock); } { ParallelModeEnabler enabler(*m_slotVisitor); diff --git a/Source/JavaScriptCore/heap/GCThreadSharedData.cpp b/Source/JavaScriptCore/heap/GCThreadSharedData.cpp index d9946d589..446b41c2f 100644 --- a/Source/JavaScriptCore/heap/GCThreadSharedData.cpp +++ b/Source/JavaScriptCore/heap/GCThreadSharedData.cpp @@ -61,13 +61,16 @@ GCThreadSharedData::GCThreadSharedData(JSGlobalData* globalData) , m_parallelMarkersShouldExit(false) , m_blocksToCopy(globalData->heap.m_blockSnapshot) , m_copyIndex(0) + , m_numberOfActiveGCThreads(0) + , m_gcThreadsShouldWait(false) , m_currentPhase(NoPhase) { m_copyLock.Init(); #if ENABLE(PARALLEL_GC) // Grab the lock so the new GC threads can be properly initialized before they start running. - MutexLocker locker(m_markingLock); + MutexLocker locker(m_phaseLock); for (unsigned i = 1; i < Options::numberOfGCMarkers(); ++i) { + m_numberOfActiveGCThreads++; SlotVisitor* slotVisitor = new SlotVisitor(*this); CopyVisitor* copyVisitor = new CopyVisitor(*this); GCThread* newThread = new GCThread(*this, slotVisitor, copyVisitor); @@ -75,6 +78,10 @@ GCThreadSharedData::GCThreadSharedData(JSGlobalData* globalData) newThread->initializeThreadID(threadID); m_gcThreads.append(newThread); } + + // Wait for all the GCThreads to get to the right place. + while (m_numberOfActiveGCThreads) + m_activityCondition.wait(m_phaseLock); #endif } @@ -87,6 +94,7 @@ GCThreadSharedData::~GCThreadSharedData() MutexLocker phaseLocker(m_phaseLock); ASSERT(m_currentPhase == NoPhase); m_parallelMarkersShouldExit = true; + m_gcThreadsShouldWait = false; m_currentPhase = Exit; m_phaseCondition.broadcast(); } @@ -115,24 +123,44 @@ void GCThreadSharedData::reset() } } -void GCThreadSharedData::didStartMarking() +void GCThreadSharedData::startNextPhase(GCPhase phase) { - MutexLocker markingLocker(m_markingLock); MutexLocker phaseLocker(m_phaseLock); + ASSERT(!m_gcThreadsShouldWait); ASSERT(m_currentPhase == NoPhase); - m_currentPhase = Mark; - m_parallelMarkersShouldExit = false; + m_gcThreadsShouldWait = true; + m_currentPhase = phase; m_phaseCondition.broadcast(); } -void GCThreadSharedData::didFinishMarking() +void GCThreadSharedData::endCurrentPhase() +{ + ASSERT(m_gcThreadsShouldWait); + MutexLocker locker(m_phaseLock); + m_currentPhase = NoPhase; + m_gcThreadsShouldWait = false; + m_phaseCondition.broadcast(); + while (m_numberOfActiveGCThreads) + m_activityCondition.wait(m_phaseLock); +} + +void GCThreadSharedData::didStartMarking() { MutexLocker markingLocker(m_markingLock); - MutexLocker phaseLocker(m_phaseLock); + m_parallelMarkersShouldExit = false; + startNextPhase(Mark); +} + +void GCThreadSharedData::didFinishMarking() +{ + { + MutexLocker markingLocker(m_markingLock); + m_parallelMarkersShouldExit = true; + m_markingCondition.broadcast(); + } + ASSERT(m_currentPhase == Mark); - m_currentPhase = NoPhase; - m_parallelMarkersShouldExit = true; - m_markingCondition.broadcast(); + endCurrentPhase(); } void GCThreadSharedData::didStartCopying() @@ -150,18 +178,13 @@ void GCThreadSharedData::didStartCopying() for (size_t i = 0; i < m_gcThreads.size(); i++) m_gcThreads[i]->copyVisitor()->startCopying(); - MutexLocker locker(m_phaseLock); - ASSERT(m_currentPhase == NoPhase); - m_currentPhase = Copy; - m_phaseCondition.broadcast(); + startNextPhase(Copy); } void GCThreadSharedData::didFinishCopying() { - MutexLocker locker(m_phaseLock); ASSERT(m_currentPhase == Copy); - m_currentPhase = NoPhase; - m_phaseCondition.broadcast(); + endCurrentPhase(); } } // namespace JSC diff --git a/Source/JavaScriptCore/heap/GCThreadSharedData.h b/Source/JavaScriptCore/heap/GCThreadSharedData.h index bd48d9263..f341afc04 100644 --- a/Source/JavaScriptCore/heap/GCThreadSharedData.h +++ b/Source/JavaScriptCore/heap/GCThreadSharedData.h @@ -74,6 +74,8 @@ private: friend class CopyVisitor; void getNextBlocksToCopy(size_t&, size_t&); + void startNextPhase(GCPhase); + void endCurrentPhase(); JSGlobalData* m_globalData; CopiedSpace* m_copiedSpace; @@ -100,6 +102,9 @@ private: Mutex m_phaseLock; ThreadCondition m_phaseCondition; + ThreadCondition m_activityCondition; + unsigned m_numberOfActiveGCThreads; + bool m_gcThreadsShouldWait; GCPhase m_currentPhase; ListableHandler<WeakReferenceHarvester>::List m_weakReferenceHarvesters; diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp index 772d85144..cd3393aa2 100644 --- a/Source/JavaScriptCore/heap/Heap.cpp +++ b/Source/JavaScriptCore/heap/Heap.cpp @@ -612,10 +612,9 @@ void Heap::copyBackingStores() m_storageSpace.startedCopying(); if (m_storageSpace.shouldDoCopyPhase()) { m_sharedData.didStartCopying(); - CopyVisitor& visitor = m_copyVisitor; - visitor.startCopying(); - visitor.copyFromShared(); - visitor.doneCopying(); + m_copyVisitor.startCopying(); + m_copyVisitor.copyFromShared(); + m_copyVisitor.doneCopying(); // We need to wait for everybody to finish and return their CopiedBlocks // before signaling that the phase is complete. m_storageSpace.doneCopying(); diff --git a/Source/JavaScriptCore/heap/SlotVisitor.cpp b/Source/JavaScriptCore/heap/SlotVisitor.cpp index 26d056feb..7a30debda 100644 --- a/Source/JavaScriptCore/heap/SlotVisitor.cpp +++ b/Source/JavaScriptCore/heap/SlotVisitor.cpp @@ -10,6 +10,7 @@ #include "JSGlobalData.h" #include "JSObject.h" #include "JSString.h" +#include <wtf/StackStats.h> namespace JSC { @@ -58,6 +59,7 @@ void SlotVisitor::reset() void SlotVisitor::append(ConservativeRoots& conservativeRoots) { + StackStats::probe(); JSCell** roots = conservativeRoots.roots(); size_t size = conservativeRoots.size(); for (size_t i = 0; i < size; ++i) @@ -66,6 +68,7 @@ void SlotVisitor::append(ConservativeRoots& conservativeRoots) ALWAYS_INLINE static void visitChildren(SlotVisitor& visitor, const JSCell* cell) { + StackStats::probe(); #if ENABLE(SIMPLE_HEAP_PROFILING) m_visitedTypeCounts.count(cell); #endif @@ -92,6 +95,7 @@ ALWAYS_INLINE static void visitChildren(SlotVisitor& visitor, const JSCell* cell void SlotVisitor::donateKnownParallel() { + StackStats::probe(); // NOTE: Because we re-try often, we can afford to be conservative, and // assume that donating is not profitable. @@ -119,6 +123,7 @@ void SlotVisitor::donateKnownParallel() void SlotVisitor::drain() { + StackStats::probe(); ASSERT(m_isInParallelMode); #if ENABLE(PARALLEL_GC) @@ -144,6 +149,7 @@ void SlotVisitor::drain() void SlotVisitor::drainFromShared(SharedDrainMode sharedDrainMode) { + StackStats::probe(); ASSERT(m_isInParallelMode); ASSERT(Options::numberOfGCMarkers()); @@ -221,6 +227,7 @@ void SlotVisitor::drainFromShared(SharedDrainMode sharedDrainMode) void SlotVisitor::mergeOpaqueRoots() { + StackStats::probe(); ASSERT(!m_opaqueRoots.isEmpty()); // Should only be called when opaque roots are non-empty. { MutexLocker locker(m_shared.m_opaqueRootsLock); @@ -276,6 +283,7 @@ ALWAYS_INLINE void SlotVisitor::internalAppend(JSValue* slot) // as it can change the JSValue pointed to be the argument when the original JSValue // is a string that contains the same contents as another string. + StackStats::probe(); ASSERT(slot); JSValue value = *slot; ASSERT(value); @@ -309,12 +317,14 @@ ALWAYS_INLINE void SlotVisitor::internalAppend(JSValue* slot) void SlotVisitor::harvestWeakReferences() { + StackStats::probe(); for (WeakReferenceHarvester* current = m_shared.m_weakReferenceHarvesters.head(); current; current = current->next()) current->visitWeakReferences(*this); } void SlotVisitor::finalizeUnconditionalFinalizers() { + StackStats::probe(); while (m_shared.m_unconditionalFinalizers.hasNext()) m_shared.m_unconditionalFinalizers.removeNext()->finalizeUnconditionally(); } |