Chromium Code Reviews| Index: Source/platform/heap/Heap.cpp |
| diff --git a/Source/platform/heap/Heap.cpp b/Source/platform/heap/Heap.cpp |
| index 5b22fc005fe02f671dabda31ac24c08980abb24e..1ac77326969df1a8acde065f31e13ce5af8ad282 100644 |
| --- a/Source/platform/heap/Heap.cpp |
| +++ b/Source/platform/heap/Heap.cpp |
| @@ -111,8 +111,16 @@ static String classOf(const void* object) |
| class GCScope { |
| public: |
| - explicit GCScope(ThreadState::StackState stackState) |
| + static GCScope* current() |
| + { |
| + ASSERT(ThreadState::current()->isInGC()); |
| + ASSERT(s_currentGCScope); |
| + return s_currentGCScope; |
| + } |
| + |
| + GCScope(ThreadState::StackState stackState, ThreadState::GCType gcType) |
| : m_state(ThreadState::current()) |
| + , m_gcType(gcType) |
| , m_safePointScope(stackState) |
| , m_parkedAllThreads(false) |
| { |
| @@ -131,12 +139,17 @@ public: |
| } |
| if (m_state->isMainThread()) |
| TRACE_EVENT_SET_NONCONST_SAMPLING_STATE(samplingState); |
| + |
| + ASSERT(!s_currentGCScope); |
| + s_currentGCScope = this; |
| } |
| - bool allThreadsParked() { return m_parkedAllThreads; } |
| + bool allThreadsParked() const { return m_parkedAllThreads; } |
| + ThreadState::GCType gcType() const { return m_gcType; } |
| ~GCScope() |
| { |
| + s_currentGCScope = nullptr; |
| // Only cleanup if we parked all threads in which case the GC happened |
| // and we need to resume the other threads. |
| if (LIKELY(m_parkedAllThreads)) { |
| @@ -146,10 +159,15 @@ public: |
| private: |
| ThreadState* m_state; |
| + ThreadState::GCType m_gcType; |
| SafePointScope m_safePointScope; |
| bool m_parkedAllThreads; // False if we fail to park all threads |
| + |
| + static GCScope* s_currentGCScope; |
| }; |
| +GCScope* GCScope::s_currentGCScope = nullptr; |
| + |
| #if ENABLE(ASSERT) |
| NO_SANITIZE_ADDRESS |
| void HeapObjectHeader::zapMagic() |
| @@ -299,6 +317,28 @@ void BaseHeap::makeConsistentForGC() |
| ASSERT(!m_firstUnsweptPage); |
| } |
| +void BaseHeap::makeConsistentForMutator() |
| +{ |
| + clearFreeLists(); |
| + ASSERT(isConsistentForGC()); |
| + ASSERT(!m_firstPage); |
| + |
| + // Drop marks from marked objects and rebuild free lists in preparation for |
| + // resuming the executions of mutators. |
| + BasePage* previousPage = nullptr; |
| + for (BasePage* page = m_firstUnsweptPage; page; previousPage = page, page = page->next()) { |
| + page->makeConsistentForMutator(); |
| + page->markAsSwept(); |
| + } |
| + if (previousPage) { |
| + ASSERT(m_firstUnsweptPage); |
| + previousPage->m_next = m_firstPage; |
| + m_firstPage = m_firstUnsweptPage; |
| + m_firstUnsweptPage = nullptr; |
| + } |
| + ASSERT(!m_firstUnsweptPage); |
| +} |
| + |
| size_t BaseHeap::objectPayloadSizeForTesting() |
| { |
| ASSERT(isConsistentForGC()); |
| @@ -320,7 +360,7 @@ void BaseHeap::prepareHeapForTermination() |
| void BaseHeap::prepareForSweep() |
| { |
| - ASSERT(!threadState()->isInGC()); |
| + ASSERT(threadState()->isInGC()); |
| ASSERT(!m_firstUnsweptPage); |
| // Move all pages to a list of unswept pages. |
| @@ -1179,6 +1219,37 @@ void NormalPage::makeConsistentForGC() |
| Heap::increaseMarkedObjectSize(markedObjectSize); |
| } |
| +void NormalPage::makeConsistentForMutator() |
| +{ |
| + size_t markedObjectSize = 0; |
| + Address startOfGap = payload(); |
| + for (Address headerAddress = payload(); headerAddress < payloadEnd();) { |
| + HeapObjectHeader* header = reinterpret_cast<HeapObjectHeader*>(headerAddress); |
| + ASSERT(header->size() < blinkPagePayloadSize()); |
| + // Check if a free list entry first since we cannot call |
| + // isMarked on a free list entry. |
| + if (header->isFree()) { |
| + headerAddress += header->size(); |
| + continue; |
| + } |
| + header->checkHeader(); |
| + |
| + if (startOfGap != headerAddress) |
| + heapForNormalPage()->addToFreeList(startOfGap, headerAddress - startOfGap); |
| + if (header->isMarked()) { |
| + header->unmark(); |
| + markedObjectSize += header->size(); |
| + } |
| + headerAddress += header->size(); |
| + startOfGap = headerAddress; |
| + } |
| + if (startOfGap != payloadEnd()) |
| + heapForNormalPage()->addToFreeList(startOfGap, payloadEnd() - startOfGap); |
| + |
| + if (markedObjectSize) |
| + Heap::increaseMarkedObjectSize(markedObjectSize); |
| +} |
| + |
| #if defined(ADDRESS_SANITIZER) |
| void NormalPage::poisonUnmarkedObjects() |
| { |
| @@ -1468,6 +1539,15 @@ void LargeObjectPage::makeConsistentForGC() |
| } |
| } |
| +void LargeObjectPage::makeConsistentForMutator() |
| +{ |
| + HeapObjectHeader* header = heapObjectHeader(); |
| + if (header->isMarked()) { |
| + header->unmark(); |
| + Heap::increaseMarkedObjectSize(size()); |
| + } |
| +} |
| + |
| #if defined(ADDRESS_SANITIZER) |
| void LargeObjectPage::poisonUnmarkedObjects() |
| { |
| @@ -1760,6 +1840,8 @@ String Heap::createBacktraceString() |
| void Heap::pushTraceCallback(void* object, TraceCallback callback) |
| { |
| + ASSERT(ThreadState::current()->isInGC()); |
| + |
| // Trace should never reach an orphaned page. |
| ASSERT(!Heap::orphanedPagePool()->contains(object)); |
| CallbackStack::Item* slot = s_markingStack->allocateEntry(); |
| @@ -1781,6 +1863,8 @@ bool Heap::popAndInvokeTraceCallback(Visitor* visitor) |
| void Heap::pushPostMarkingCallback(void* object, TraceCallback callback) |
| { |
| + ASSERT(ThreadState::current()->isInGC()); |
| + |
| // Trace should never reach an orphaned page. |
| ASSERT(!Heap::orphanedPagePool()->contains(object)); |
| CallbackStack::Item* slot = s_postMarkingCallbackStack->allocateEntry(); |
| @@ -1798,6 +1882,11 @@ bool Heap::popAndInvokePostMarkingCallback(Visitor* visitor) |
| void Heap::pushGlobalWeakCallback(void** cell, WeakCallback callback) |
| { |
| + ASSERT(ThreadState::current()->isInGC()); |
| + // We don't want to run weak processings when taking a snapshot. |
| + if (GCScope::current()->gcType() == ThreadState::TakeSnapshot) |
|
sof
2015/05/30 20:50:06
Did you explore providing MarkingVisitor<GlobalMar
|
| + return; |
| + |
| // Trace should never reach an orphaned page. |
| ASSERT(!Heap::orphanedPagePool()->contains(cell)); |
| CallbackStack::Item* slot = s_globalWeakCallbackStack->allocateEntry(); |
| @@ -1806,6 +1895,11 @@ void Heap::pushGlobalWeakCallback(void** cell, WeakCallback callback) |
| void Heap::pushThreadLocalWeakCallback(void* closure, void* object, WeakCallback callback) |
| { |
| + ASSERT(ThreadState::current()->isInGC()); |
| + // We don't want to run weak processings when taking a snapshot. |
| + if (GCScope::current()->gcType() == ThreadState::TakeSnapshot) |
| + return; |
| + |
| // Trace should never reach an orphaned page. |
| ASSERT(!Heap::orphanedPagePool()->contains(object)); |
| ThreadState* state = pageFromObject(object)->heap()->threadState(); |
| @@ -1823,6 +1917,8 @@ bool Heap::popAndInvokeGlobalWeakCallback(Visitor* visitor) |
| void Heap::registerWeakTable(void* table, EphemeronCallback iterationCallback, EphemeronCallback iterationDoneCallback) |
| { |
| + ASSERT(ThreadState::current()->isInGC()); |
| + |
| // Trace should never reach an orphaned page. |
| ASSERT(!Heap::orphanedPagePool()->contains(table)); |
| CallbackStack::Item* slot = s_ephemeronStack->allocateEntry(); |
| @@ -1877,7 +1973,7 @@ void Heap::collectGarbage(ThreadState::StackState stackState, ThreadState::GCTyp |
| ThreadState::GCState originalGCState = state->gcState(); |
| state->setGCState(ThreadState::StoppingOtherThreads); |
| - GCScope gcScope(stackState); |
| + GCScope gcScope(stackState, gcType); |
| // Check if we successfully parked the other threads. If not we bail out of |
| // the GC. |
| if (!gcScope.allThreadsParked()) { |