Chromium Code Reviews| Index: third_party/WebKit/Source/platform/heap/ThreadState.cpp |
| diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/third_party/WebKit/Source/platform/heap/ThreadState.cpp |
| index 05b9138f4a58a6ad7ea205c8ab6df4559431fb0e..19ac3d8d0ce3a8bdad45dff13aa8d97190c51350 100644 |
| --- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp |
| +++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp |
| @@ -36,7 +36,9 @@ |
| #include "platform/heap/CallbackStack.h" |
| #include "platform/heap/Handle.h" |
| #include "platform/heap/Heap.h" |
| +#include "platform/heap/HeapPage.h" |
| #include "platform/heap/MarkingVisitor.h" |
| +#include "platform/heap/PagePool.h" |
| #include "platform/heap/SafePoint.h" |
| #include "public/platform/Platform.h" |
| #include "public/platform/WebMemoryAllocatorDump.h" |
| @@ -66,24 +68,281 @@ extern "C" void* __libc_stack_end; // NOLINT |
| namespace blink { |
| +GCHeapStats::GCHeapStats() |
| + : m_allocatedSpace(0) |
| + , m_allocatedObjectSize(0) |
| + , m_objectSizeAtLastGC(0) |
| + , m_markedObjectSize(0) |
| + , m_markedObjectSizeAtLastCompleteSweep(0) |
| + , m_wrapperCount(0) |
| + , m_wrapperCountAtLastGC(0) |
| + , m_collectedWrapperCount(0) |
| + , m_partitionAllocSizeAtLastGC(WTF::Partitions::totalSizeOfCommittedPages()) |
| + , m_estimatedMarkingTimePerByte(0.0) |
| +{ |
| +} |
| + |
| +double GCHeapStats::estimatedMarkingTime() |
| +{ |
| + // Use 8 ms as initial estimated marking time. |
| + // 8 ms is long enough for low-end mobile devices to mark common |
| + // real-world object graphs. |
| + if (m_estimatedMarkingTimePerByte == 0) |
| + return 0.008; |
| + |
| + // Assuming that the collection rate of this GC will be mostly equal to |
| + // the collection rate of the last GC, estimate the marking time of this GC. |
| + return m_estimatedMarkingTimePerByte * (allocatedObjectSize() + markedObjectSize()); |
| +} |
| + |
| +void GCHeapStats::reset() |
| +{ |
| + m_objectSizeAtLastGC = m_allocatedObjectSize + m_markedObjectSize; |
| + m_partitionAllocSizeAtLastGC = WTF::Partitions::totalSizeOfCommittedPages(); |
|
haraken
2016/02/12 11:28:52
It would be problematic to simply use PartitionAll
|
| + m_allocatedObjectSize = 0; |
| + m_markedObjectSize = 0; |
| + m_wrapperCountAtLastGC = m_wrapperCount; |
| + m_collectedWrapperCount = 0; |
| +} |
| + |
| +void GCHeapStats::increaseAllocatedObjectSize(size_t delta) |
|
haraken
2016/02/12 11:28:52
These changes will be made by peria-san's CL:
htt
|
| +{ |
| + atomicAdd(&m_allocatedObjectSize, static_cast<long>(delta)); |
| + Heap::increaseTotalAllocatedObjectSize(delta); |
| +} |
| + |
| +void GCHeapStats::decreaseAllocatedObjectSize(size_t delta) |
| +{ |
| + atomicSubtract(&m_allocatedObjectSize, static_cast<long>(delta)); |
| + Heap::decreaseTotalAllocatedObjectSize(delta); |
| +} |
| + |
| +void GCHeapStats::increaseMarkedObjectSize(size_t delta) |
| +{ |
| + atomicAdd(&m_markedObjectSize, static_cast<long>(delta)); |
| + Heap::increaseTotalMarkedObjectSize(delta); |
| +} |
| + |
| +void GCHeapStats::increaseAllocatedSpace(size_t delta) |
| +{ |
| + atomicAdd(&m_allocatedSpace, static_cast<long>(delta)); |
| + Heap::increaseTotalAllocatedSpace(delta); |
| +} |
| + |
| +void GCHeapStats::decreaseAllocatedSpace(size_t delta) |
| +{ |
| + atomicSubtract(&m_allocatedSpace, static_cast<long>(delta)); |
| + Heap::decreaseTotalAllocatedSpace(delta); |
| +} |
| + |
| +HashSet<GCGroup*>& GCGroup::all() |
| +{ |
| + DEFINE_STATIC_LOCAL(HashSet<GCGroup*>, groups, ()); |
| + return groups; |
| +} |
| + |
| +GCGroup::GCGroup() |
| + : m_regionTree(nullptr) |
| + , m_heapDoesNotContainCache(adoptPtr(new HeapDoesNotContainCache)) |
| +{ |
| +} |
| + |
| +GCGroup::~GCGroup() |
| +{ |
| +} |
| + |
| +void GCGroup::flushHeapDoesNotContainCache() |
| +{ |
| + m_heapDoesNotContainCache->flush(); |
| +} |
| + |
| +MultiThreadGCGroup::MultiThreadGCGroup() |
| + : m_safePointBarrier(adoptPtr(new SafePointBarrier(this))) |
| + , m_freePagePool(adoptPtr(new FreePagePool)) |
|
haraken
2016/02/12 11:28:52
Maybe we should share the FreePagePool among all t
|
| + , m_orphanedPagePool(adoptPtr(new OrphanedPagePool)) |
| +{ |
| + GCGroup::all().add(this); |
| +} |
| + |
| +MultiThreadGCGroup::~MultiThreadGCGroup() |
| +{ |
| + GCGroup::all().remove(this); |
| +} |
| + |
| +void MultiThreadGCGroup::attach(ThreadState* thread) |
| +{ |
| + MutexLocker locker(m_threadAttachMutex); |
| + m_threads.add(thread); |
| +} |
| + |
| +void MultiThreadGCGroup::detach(ThreadState* thread) |
| +{ |
| + SafePointAwareMutexLocker locker(m_threadAttachMutex, BlinkGC::NoHeapPointersOnStack); |
| + thread->cleanupCallback(); |
| + ASSERT(m_threads.contains(thread)); |
| + m_threads.remove(thread); |
| +} |
| + |
| +bool MultiThreadGCGroup::park() |
| +{ |
| + return m_safePointBarrier->parkOthers(); |
| +} |
| + |
| +void MultiThreadGCGroup::resume() |
| +{ |
| + m_safePointBarrier->resumeOthers(); |
| +} |
| + |
| +bool MultiThreadGCGroup::isParked() const |
|
haraken
2016/02/12 11:28:52
Add #if ENABLE(ASSERT).
haraken
2016/02/12 11:28:52
isParked => isAtSafePoint
keishi
2016/02/29 06:02:33
Done.
keishi
2016/02/29 06:02:33
Done.
|
| +{ |
| + for (ThreadState* state : m_threads) { |
| + if (!state->isAtSafePoint()) |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| +void MultiThreadGCGroup::lockThreadAttachMutex() |
| +{ |
| + m_threadAttachMutex.lock(); |
| +} |
| + |
| +void MultiThreadGCGroup::unlockThreadAttachMutex() |
| +{ |
| + m_threadAttachMutex.unlock(); |
| +} |
| + |
| +#if ENABLE(ASSERT) |
| +BasePage* MultiThreadGCGroup::findPageFromAddress(Address address) |
| +{ |
| + for (ThreadState* state : m_threads) { |
| + if (BasePage* page = state->findPageFromAddress(address)) |
| + return page; |
| + } |
| + return nullptr; |
| +} |
| +#endif |
| + |
| +void MultiThreadGCGroup::preGC() |
| +{ |
| + for (ThreadState* state : m_threads) { |
| + state->preGC(); |
| + } |
| +} |
| + |
| +void MultiThreadGCGroup::postGC(BlinkGC::GCType gcType) |
| +{ |
| + for (ThreadState* state : m_threads) { |
| + state->postGC(gcType); |
| + } |
| +} |
| + |
| +size_t MultiThreadGCGroup::objectPayloadSizeForTesting() |
| +{ |
| + size_t objectPayloadSize = 0; |
| + for (ThreadState* state : m_threads) { |
| + state->setGCState(ThreadState::GCRunning); |
| + state->makeConsistentForGC(); |
| + objectPayloadSize += state->objectPayloadSizeForTesting(); |
| + state->setGCState(ThreadState::EagerSweepScheduled); |
| + state->setGCState(ThreadState::Sweeping); |
| + state->setGCState(ThreadState::NoGCScheduled); |
| + } |
| + return objectPayloadSize; |
| +} |
| + |
| +size_t MultiThreadGCGroup::size() const |
|
haraken
2016/02/12 11:28:52
size => threadCount ?
keishi
2016/02/29 06:02:34
Done.
|
| +{ |
| + return m_threads.size(); |
| +} |
| + |
| +void MultiThreadGCGroup::visitPersistentRoots(Visitor* visitor) |
| +{ |
| + TRACE_EVENT0("blink_gc", "ThreadState::visitPersistentRoots"); |
| + Heap::crossThreadPersistentRegion().tracePersistentNodes(visitor); |
| + |
| + for (ThreadState* state : m_threads) { |
| + state->visitPersistents(visitor); |
| + } |
| +} |
| + |
| +void MultiThreadGCGroup::visitStackRoots(Visitor* visitor) |
| +{ |
| + TRACE_EVENT0("blink_gc", "ThreadState::visitStackRoots"); |
| + for (ThreadState* state : m_threads) { |
| + state->visitStack(visitor); |
| + } |
| +} |
| + |
| +void MultiThreadGCGroup::checkAndPark(ThreadState* threadState, SafePointAwareMutexLocker* locker) |
| +{ |
| + m_safePointBarrier->checkAndPark(threadState, locker); |
| +} |
| + |
| +void MultiThreadGCGroup::enterSafePoint(ThreadState* threadState) |
| +{ |
| + m_safePointBarrier->enterSafePoint(threadState); |
| +} |
| + |
| +void MultiThreadGCGroup::leaveSafePoint(ThreadState* threadState, SafePointAwareMutexLocker* locker) |
| +{ |
| + m_safePointBarrier->leaveSafePoint(threadState, locker); |
| +} |
| + |
| +void MultiThreadGCGroup::shutdown() |
| +{ |
| + Heap::shutdown(); |
| +} |
| + |
| +void MultiThreadGCGroup::shutdownIfNecessary() |
| +{ |
| + MutexLocker locker(m_threadAttachMutex); |
| + if (m_threads.size() == 0 && Heap::s_shutdownCalled) { |
| + shutdown(); |
|
haraken
2016/02/12 11:28:52
As commented in Heap::shutdown(), I think we need
|
| + delete this; |
| + } |
| +} |
| + |
| +BasePage* GCGroup::lookupPageForAddress(Address address) |
| +{ |
| + ASSERT(ThreadState::current()->isInGC()); |
| + if (!m_regionTree) |
| + return nullptr; |
| + if (PageMemoryRegion* region = m_regionTree->lookup(address)) { |
| + BasePage* page = region->pageFromAddress(address); |
| + return page && !page->orphaned() ? page : nullptr; |
| + } |
| + return nullptr; |
| +} |
| + |
| +void GCGroup::addPageMemoryRegion(PageMemoryRegion* region) |
| +{ |
| + MutexLocker locker(m_regionTreeMutex); |
| + RegionTree::add(new RegionTree(region), &m_regionTree); |
| +} |
| + |
| +void GCGroup::removePageMemoryRegion(PageMemoryRegion* region) |
| +{ |
| + // Deletion of large objects (and thus their regions) can happen |
| + // concurrently on sweeper threads. Removal can also happen during thread |
| + // shutdown, but that case is safe. Regardless, we make all removals |
| + // mutually exclusive. |
| + MutexLocker locker(m_regionTreeMutex); |
| + RegionTree::remove(region, &m_regionTree); |
| +} |
| + |
| WTF::ThreadSpecific<ThreadState*>* ThreadState::s_threadSpecific = nullptr; |
| uintptr_t ThreadState::s_mainThreadStackStart = 0; |
| uintptr_t ThreadState::s_mainThreadUnderestimatedStackSize = 0; |
| uint8_t ThreadState::s_mainThreadStateStorage[sizeof(ThreadState)]; |
| -SafePointBarrier* ThreadState::s_safePointBarrier = nullptr; |
| -RecursiveMutex& ThreadState::threadAttachMutex() |
| -{ |
| - DEFINE_THREAD_SAFE_STATIC_LOCAL(RecursiveMutex, mutex, (new RecursiveMutex)); |
| - return mutex; |
| -} |
| - |
| -ThreadState::ThreadState() |
| +ThreadState::ThreadState(bool perThreadHeapEnabled) |
| : m_thread(currentThread()) |
| , m_persistentRegion(adoptPtr(new PersistentRegion())) |
| #if OS(WIN) && COMPILER(MSVC) |
| , m_threadStackSize(0) |
| #endif |
| + , m_perThreadHeapEnabled(perThreadHeapEnabled) |
| , m_startOfStack(reinterpret_cast<intptr_t*>(StackFrameDepth::getStackStart())) |
| , m_endOfStack(reinterpret_cast<intptr_t*>(StackFrameDepth::getStackStart())) |
| , m_safePointScopeMarker(nullptr) |
| @@ -100,6 +359,7 @@ ThreadState::ThreadState() |
| , m_shouldFlushHeapDoesNotContainCache(false) |
| , m_gcState(NoGCScheduled) |
| , m_traceDOMWrappers(nullptr) |
| + , m_gcGroup(nullptr) |
| #if defined(ADDRESS_SANITIZER) |
| , m_asanFakeStack(__asan_get_current_fake_stack()) |
| #endif |
| @@ -116,7 +376,14 @@ ThreadState::ThreadState() |
| size_t underestimatedStackSize = StackFrameDepth::getUnderestimatedStackSize(); |
| if (underestimatedStackSize > sizeof(void*)) |
| s_mainThreadUnderestimatedStackSize = underestimatedStackSize - sizeof(void*); |
| + m_gcGroup = new MultiThreadGCGroup(); |
| + } else if (m_perThreadHeapEnabled) { |
| + m_gcGroup = new MultiThreadGCGroup(); |
| + } else { |
| + m_gcGroup = ThreadState::mainThreadState()->gcGroup(); |
| } |
| + ASSERT(m_gcGroup); |
| + m_gcGroup->attach(this); |
| for (int heapIndex = 0; heapIndex < BlinkGC::LargeObjectHeapIndex; heapIndex++) |
| m_heaps[heapIndex] = new NormalPageHeap(this, heapIndex); |
| @@ -146,14 +413,10 @@ ThreadState::~ThreadState() |
| void ThreadState::init() |
| { |
| s_threadSpecific = new WTF::ThreadSpecific<ThreadState*>(); |
| - s_safePointBarrier = new SafePointBarrier; |
| } |
| void ThreadState::shutdown() |
| { |
| - delete s_safePointBarrier; |
| - s_safePointBarrier = nullptr; |
| - |
| // Thread-local storage shouldn't be disposed, so we don't call ~ThreadSpecific(). |
| } |
| @@ -192,12 +455,10 @@ size_t ThreadState::threadStackSize() |
| } |
| #endif |
| -void ThreadState::attachMainThread() |
| +void ThreadState::prepareForMainThread() |
| { |
| RELEASE_ASSERT(!Heap::s_shutdownCalled); |
| - MutexLocker locker(threadAttachMutex()); |
| - ThreadState* state = new(s_mainThreadStateStorage) ThreadState(); |
| - attachedThreads().add(state); |
| + new(s_mainThreadStateStorage) ThreadState(false); |
| } |
| void ThreadState::detachMainThread() |
| @@ -207,41 +468,19 @@ void ThreadState::detachMainThread() |
| // threadAttachMutex and waiting for other threads to pause or reach a |
| // safepoint. |
| ThreadState* state = mainThreadState(); |
| + GCGroup* gcGroup = state->gcGroup(); |
| // 1. Finish sweeping. |
| state->completeSweep(); |
| - { |
| - SafePointAwareMutexLocker locker(threadAttachMutex(), BlinkGC::NoHeapPointersOnStack); |
| - |
| - // 2. Add the main thread's heap pages to the orphaned pool. |
| - state->cleanupPages(); |
| - |
| - // 3. Detach the main thread. |
| - ASSERT(attachedThreads().contains(state)); |
| - attachedThreads().remove(state); |
| - state->~ThreadState(); |
| - } |
| - shutdownHeapIfNecessary(); |
| -} |
| - |
| -void ThreadState::shutdownHeapIfNecessary() |
| -{ |
| - // We don't need to enter a safe point before acquiring threadAttachMutex |
| - // because this thread is already detached. |
| - |
| - MutexLocker locker(threadAttachMutex()); |
| - // We start shutting down the heap if there is no running thread |
| - // and Heap::shutdown() is already called. |
| - if (!attachedThreads().size() && Heap::s_shutdownCalled) |
| - Heap::doShutdown(); |
| + gcGroup->detach(state); |
| + state->~ThreadState(); |
| + gcGroup->shutdownIfNecessary(); |
| } |
| -void ThreadState::attach() |
| +void ThreadState::prepareForCurrentThread(bool perThreadHeap) |
| { |
| RELEASE_ASSERT(!Heap::s_shutdownCalled); |
| - MutexLocker locker(threadAttachMutex()); |
| - ThreadState* state = new ThreadState(); |
| - attachedThreads().add(state); |
| + new ThreadState(perThreadHeap); |
| } |
| void ThreadState::cleanupPages() |
| @@ -251,81 +490,57 @@ void ThreadState::cleanupPages() |
| m_heaps[i]->cleanupPages(); |
| } |
| -void ThreadState::cleanup() |
| +void ThreadState::cleanupCallback() |
|
haraken
2016/02/12 11:28:52
cleanupCallback => cleanupThreadHeap ?
keishi
2016/02/29 06:02:33
Done.
|
| { |
| - ASSERT(checkThread()); |
| - { |
| - // Grab the threadAttachMutex to ensure only one thread can shutdown at |
| - // a time and that no other thread can do a global GC. It also allows |
| - // safe iteration of the attachedThreads set which happens as part of |
| - // thread local GC asserts. We enter a safepoint while waiting for the |
| - // lock to avoid a dead-lock where another thread has already requested |
| - // GC. |
| - SafePointAwareMutexLocker locker(threadAttachMutex(), BlinkGC::NoHeapPointersOnStack); |
| - |
| - // Finish sweeping. |
| - completeSweep(); |
| - |
| - // From here on ignore all conservatively discovered |
| - // pointers into the heap owned by this thread. |
| - m_isTerminating = true; |
| - |
| - // Set the terminate flag on all heap pages of this thread. This is used to |
| - // ensure we don't trace pages on other threads that are not part of the |
| - // thread local GC. |
| - prepareForThreadStateTermination(); |
| - |
| - Heap::crossThreadPersistentRegion().prepareForThreadStateTermination(this); |
| - |
| - // Do thread local GC's as long as the count of thread local Persistents |
| - // changes and is above zero. |
| - int oldCount = -1; |
| - int currentCount = persistentRegion()->numberOfPersistents(); |
| - ASSERT(currentCount >= 0); |
| - while (currentCount != oldCount) { |
| - Heap::collectGarbageForTerminatingThread(this); |
| - oldCount = currentCount; |
| - currentCount = persistentRegion()->numberOfPersistents(); |
| - } |
| - // We should not have any persistents left when getting to this point, |
| - // if we have it is probably a bug so adding a debug ASSERT to catch this. |
| - ASSERT(!currentCount); |
| - // All of pre-finalizers should be consumed. |
| - ASSERT(m_orderedPreFinalizers.isEmpty()); |
| - RELEASE_ASSERT(gcState() == NoGCScheduled); |
| - |
| - // Add pages to the orphaned page pool to ensure any global GCs from this point |
| - // on will not trace objects on this thread's heaps. |
| + if (isMainThread()) { |
|
haraken
2016/02/12 11:28:52
This should be:
if (isMainThread() || m_perThre
keishi
2016/02/29 06:02:33
Done.
|
| cleanupPages(); |
| + return; |
| + } |
| - ASSERT(attachedThreads().contains(this)); |
| - attachedThreads().remove(this); |
| + // Finish sweeping. |
| + completeSweep(); |
| + |
| + // From here on ignore all conservatively discovered |
| + // pointers into the heap owned by this thread. |
| + m_isTerminating = true; |
| + |
| + // Set the terminate flag on all heap pages of this thread. This is used to |
| + // ensure we don't trace pages on other threads that are not part of the |
| + // thread local GC. |
| + prepareForThreadStateTermination(); |
| + |
| + Heap::crossThreadPersistentRegion().prepareForThreadStateTermination(this); |
| + |
| + // Do thread local GC's as long as the count of thread local Persistents |
| + // changes and is above zero. |
| + int oldCount = -1; |
| + int currentCount = persistentRegion()->numberOfPersistents(); |
| + ASSERT(currentCount >= 0); |
| + while (currentCount != oldCount) { |
| + Heap::collectGarbageForTerminatingThread(this); |
| + oldCount = currentCount; |
| + currentCount = persistentRegion()->numberOfPersistents(); |
| } |
|
haraken
2016/02/12 11:28:52
If m_perThreadHeapEnabled is true, the termination
|
| + // We should not have any persistents left when getting to this point, |
| + // if we have it is probably a bug so adding a debug ASSERT to catch this. |
| + ASSERT(!currentCount); |
| + // All of pre-finalizers should be consumed. |
| + ASSERT(m_orderedPreFinalizers.isEmpty()); |
| + RELEASE_ASSERT(gcState() == NoGCScheduled); |
| + |
| + // Add pages to the orphaned page pool to ensure any global GCs from this point |
| + // on will not trace objects on this thread's heaps. |
| + cleanupPages(); |
| } |
| void ThreadState::detach() |
| { |
| ThreadState* state = current(); |
| - state->cleanup(); |
| + GCGroup* gcGroup = state->gcGroup(); |
| + gcGroup->detach(state); |
| RELEASE_ASSERT(state->gcState() == ThreadState::NoGCScheduled); |
| delete state; |
| - shutdownHeapIfNecessary(); |
| -} |
| - |
| -void ThreadState::visitPersistentRoots(Visitor* visitor) |
| -{ |
| - TRACE_EVENT0("blink_gc", "ThreadState::visitPersistentRoots"); |
| - Heap::crossThreadPersistentRegion().tracePersistentNodes(visitor); |
| - |
| - for (ThreadState* state : attachedThreads()) |
| - state->visitPersistents(visitor); |
| -} |
| - |
| -void ThreadState::visitStackRoots(Visitor* visitor) |
| -{ |
| - TRACE_EVENT0("blink_gc", "ThreadState::visitStackRoots"); |
| - for (ThreadState* state : attachedThreads()) |
| - state->visitStack(visitor); |
| + gcGroup->shutdownIfNecessary(); |
| } |
| NO_SANITIZE_ADDRESS |
| @@ -480,7 +695,7 @@ void ThreadState::threadLocalWeakProcessing() |
| // Due to the complexity, we just forbid allocations. |
| NoAllocationScope noAllocationScope(this); |
| - MarkingVisitor<Visitor::WeakProcessing> weakProcessingVisitor; |
| + MarkingVisitor<Visitor::WeakProcessing> weakProcessingVisitor(nullptr); |
| // Perform thread-specific weak processing. |
| while (popAndInvokeThreadLocalWeakCallback(&weakProcessingVisitor)) { } |
| @@ -493,18 +708,18 @@ void ThreadState::threadLocalWeakProcessing() |
| size_t ThreadState::totalMemorySize() |
| { |
| - return Heap::allocatedObjectSize() + Heap::markedObjectSize() + WTF::Partitions::totalSizeOfCommittedPages(); |
| + return gcGroup()->heapStats().allocatedObjectSize() + gcGroup()->heapStats().markedObjectSize() + WTF::Partitions::totalSizeOfCommittedPages(); |
| } |
| size_t ThreadState::estimatedLiveSize(size_t estimationBaseSize, size_t sizeAtLastGC) |
| { |
| - if (Heap::wrapperCountAtLastGC() == 0) { |
| + if (gcGroup()->heapStats().wrapperCountAtLastGC() == 0) { |
| // We'll reach here only before hitting the first GC. |
| return 0; |
| } |
| // (estimated size) = (estimation base size) - (heap size at the last GC) / (# of persistent handles at the last GC) * (# of persistent handles collected since the last GC); |
| - size_t sizeRetainedByCollectedPersistents = static_cast<size_t>(1.0 * sizeAtLastGC / Heap::wrapperCountAtLastGC() * Heap::collectedWrapperCount()); |
| + size_t sizeRetainedByCollectedPersistents = static_cast<size_t>(1.0 * sizeAtLastGC / gcGroup()->heapStats().wrapperCountAtLastGC() * gcGroup()->heapStats().collectedWrapperCount()); |
| if (estimationBaseSize < sizeRetainedByCollectedPersistents) |
| return 0; |
| return estimationBaseSize - sizeRetainedByCollectedPersistents; |
| @@ -512,8 +727,8 @@ size_t ThreadState::estimatedLiveSize(size_t estimationBaseSize, size_t sizeAtLa |
| double ThreadState::heapGrowingRate() |
| { |
| - size_t currentSize = Heap::allocatedObjectSize() + Heap::markedObjectSize(); |
| - size_t estimatedSize = estimatedLiveSize(Heap::markedObjectSizeAtLastCompleteSweep(), Heap::markedObjectSizeAtLastCompleteSweep()); |
| + size_t currentSize = gcGroup()->heapStats().allocatedObjectSize() + gcGroup()->heapStats().markedObjectSize(); |
| + size_t estimatedSize = estimatedLiveSize(gcGroup()->heapStats().markedObjectSizeAtLastCompleteSweep(), gcGroup()->heapStats().markedObjectSizeAtLastCompleteSweep()); |
| // If the estimatedSize is 0, we set a high growing rate to trigger a GC. |
| double growingRate = estimatedSize > 0 ? 1.0 * currentSize / estimatedSize : 100; |
| @@ -525,7 +740,7 @@ double ThreadState::heapGrowingRate() |
| double ThreadState::partitionAllocGrowingRate() |
| { |
| size_t currentSize = WTF::Partitions::totalSizeOfCommittedPages(); |
| - size_t estimatedSize = estimatedLiveSize(currentSize, Heap::partitionAllocSizeAtLastGC()); |
| + size_t estimatedSize = estimatedLiveSize(currentSize, gcGroup()->heapStats().partitionAllocSizeAtLastGC()); |
| // If the estimatedSize is 0, we set a high growing rate to trigger a GC. |
| double growingRate = estimatedSize > 0 ? 1.0 * currentSize / estimatedSize : 100; |
| @@ -539,7 +754,7 @@ double ThreadState::partitionAllocGrowingRate() |
| bool ThreadState::judgeGCThreshold(size_t totalMemorySizeThreshold, double heapGrowingRateThreshold) |
| { |
| // If the allocated object size or the total memory size is small, don't trigger a GC. |
| - if (Heap::allocatedObjectSize() < 100 * 1024 || totalMemorySize() < totalMemorySizeThreshold) |
| + if (gcGroup()->heapStats().allocatedObjectSize() < 100 * 1024 || totalMemorySize() < totalMemorySizeThreshold) |
| return false; |
| // If the growing rate of Oilpan's heap or PartitionAlloc is high enough, |
| // trigger a GC. |
| @@ -747,8 +962,8 @@ void ThreadState::performIdleGC(double deadlineSeconds) |
| return; |
| double idleDeltaInSeconds = deadlineSeconds - Platform::current()->monotonicallyIncreasingTimeSeconds(); |
| - TRACE_EVENT2("blink_gc", "ThreadState::performIdleGC", "idleDeltaInSeconds", idleDeltaInSeconds, "estimatedMarkingTime", Heap::estimatedMarkingTime()); |
| - if (idleDeltaInSeconds <= Heap::estimatedMarkingTime() && !Platform::current()->currentThread()->scheduler()->canExceedIdleDeadlineIfRequired()) { |
| + TRACE_EVENT2("blink_gc", "ThreadState::performIdleGC", "idleDeltaInSeconds", idleDeltaInSeconds, "estimatedMarkingTime", ThreadState::current()->gcGroup()->heapStats().estimatedMarkingTime()); |
| + if (idleDeltaInSeconds <= ThreadState::current()->gcGroup()->heapStats().estimatedMarkingTime() && !Platform::current()->currentThread()->scheduler()->canExceedIdleDeadlineIfRequired()) { |
| // If marking is estimated to take longer than the deadline and we can't |
| // exceed the deadline, then reschedule for the next idle period. |
| scheduleIdleGC(); |
| @@ -950,7 +1165,7 @@ void ThreadState::runScheduledGC(BlinkGC::StackState stackState) |
| void ThreadState::flushHeapDoesNotContainCacheIfNeeded() |
| { |
| if (m_shouldFlushHeapDoesNotContainCache) { |
| - Heap::flushHeapDoesNotContainCache(); |
| + gcGroup()->flushHeapDoesNotContainCache(); |
| m_shouldFlushHeapDoesNotContainCache = false; |
| } |
| } |
| @@ -1123,8 +1338,8 @@ void ThreadState::postSweep() |
| if (isMainThread()) { |
| double collectionRate = 0; |
| - if (Heap::objectSizeAtLastGC() > 0) |
| - collectionRate = 1 - 1.0 * Heap::markedObjectSize() / Heap::objectSizeAtLastGC(); |
| + if (gcGroup()->heapStats().objectSizeAtLastGC() > 0) |
| + collectionRate = 1 - 1.0 * gcGroup()->heapStats().markedObjectSize() / gcGroup()->heapStats().objectSizeAtLastGC(); |
| TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadState::collectionRate", static_cast<int>(100 * collectionRate)); |
| #if PRINT_HEAP_STATS |
| @@ -1133,10 +1348,10 @@ void ThreadState::postSweep() |
| // Heap::markedObjectSize() may be underestimated here if any other |
| // thread has not yet finished lazy sweeping. |
| - Heap::setMarkedObjectSizeAtLastCompleteSweep(Heap::markedObjectSize()); |
| + gcGroup()->heapStats().setMarkedObjectSizeAtLastCompleteSweep(gcGroup()->heapStats().markedObjectSize()); |
| - Platform::current()->histogramCustomCounts("BlinkGC.ObjectSizeBeforeGC", Heap::objectSizeAtLastGC() / 1024, 1, 4 * 1024 * 1024, 50); |
| - Platform::current()->histogramCustomCounts("BlinkGC.ObjectSizeAfterGC", Heap::markedObjectSize() / 1024, 1, 4 * 1024 * 1024, 50); |
| + Platform::current()->histogramCustomCounts("BlinkGC.ObjectSizeBeforeGC", gcGroup()->heapStats().objectSizeAtLastGC() / 1024, 1, 4 * 1024 * 1024, 50); |
| + Platform::current()->histogramCustomCounts("BlinkGC.ObjectSizeAfterGC", gcGroup()->heapStats().markedObjectSize() / 1024, 1, 4 * 1024 * 1024, 50); |
| Platform::current()->histogramCustomCounts("BlinkGC.CollectionRate", static_cast<int>(100 * collectionRate), 1, 100, 20); |
| Platform::current()->histogramCustomCounts("BlinkGC.TimeForSweepingAllObjects", m_accumulatedSweepingTime, 1, 10 * 1000, 50); |
| } |
| @@ -1183,16 +1398,6 @@ size_t ThreadState::objectPayloadSizeForTesting() |
| return objectPayloadSize; |
| } |
| -bool ThreadState::stopThreads() |
| -{ |
| - return s_safePointBarrier->parkOthers(); |
| -} |
| - |
| -void ThreadState::resumeThreads() |
| -{ |
| - s_safePointBarrier->resumeOthers(); |
| -} |
| - |
| void ThreadState::safePoint(BlinkGC::StackState stackState) |
| { |
| ASSERT(checkThread()); |
| @@ -1202,7 +1407,7 @@ void ThreadState::safePoint(BlinkGC::StackState stackState) |
| ASSERT(!m_atSafePoint); |
| m_stackState = stackState; |
| m_atSafePoint = true; |
| - s_safePointBarrier->checkAndPark(this); |
| + m_gcGroup->checkAndPark(this, nullptr); |
| m_atSafePoint = false; |
| m_stackState = BlinkGC::HeapPointersOnStack; |
| preSweep(); |
| @@ -1246,14 +1451,14 @@ void ThreadState::enterSafePoint(BlinkGC::StackState stackState, void* scopeMark |
| m_atSafePoint = true; |
| m_stackState = stackState; |
| m_safePointScopeMarker = scopeMarker; |
| - s_safePointBarrier->enterSafePoint(this); |
| + m_gcGroup->enterSafePoint(this); |
| } |
| void ThreadState::leaveSafePoint(SafePointAwareMutexLocker* locker) |
| { |
| ASSERT(checkThread()); |
| ASSERT(m_atSafePoint); |
| - s_safePointBarrier->leaveSafePoint(this, locker); |
| + m_gcGroup->leaveSafePoint(this, locker); |
| m_atSafePoint = false; |
| m_stackState = BlinkGC::HeapPointersOnStack; |
| clearSafePointScopeMarker(); |
| @@ -1291,7 +1496,7 @@ void ThreadState::addInterruptor(PassOwnPtr<BlinkGCInterruptor> interruptor) |
| ASSERT(checkThread()); |
| SafePointScope scope(BlinkGC::HeapPointersOnStack); |
| { |
| - MutexLocker locker(threadAttachMutex()); |
| + MutexLocker locker(gcGroup()->threadAttachMutex()); |
| m_interruptors.append(interruptor); |
| } |
| } |
| @@ -1301,7 +1506,7 @@ void ThreadState::removeInterruptor(BlinkGCInterruptor* interruptor) |
| ASSERT(checkThread()); |
| SafePointScope scope(BlinkGC::HeapPointersOnStack); |
| { |
| - MutexLocker locker(threadAttachMutex()); |
| + MutexLocker locker(gcGroup()->threadAttachMutex()); |
| size_t index = m_interruptors.find(interruptor); |
| RELEASE_ASSERT(index != kNotFound); |
| m_interruptors.remove(index); |
| @@ -1344,16 +1549,6 @@ ThreadState::AttachedThreadStateSet& ThreadState::attachedThreads() |
| return threads; |
| } |
| -void ThreadState::lockThreadAttachMutex() |
| -{ |
| - threadAttachMutex().lock(); |
| -} |
| - |
| -void ThreadState::unlockThreadAttachMutex() |
| -{ |
| - threadAttachMutex().unlock(); |
| -} |
| - |
| void ThreadState::invokePreFinalizers() |
| { |
| ASSERT(checkThread()); |
| @@ -1515,4 +1710,14 @@ void ThreadState::takeSnapshot(SnapshotType type) |
| BlinkGCMemoryDumpProvider::instance()->currentProcessMemoryDump()->addOwnershipEdge(classesDump->guid(), heapsDump->guid()); |
| } |
| +ThreadState* ThreadState::forObject(const void* object) |
|
haraken
2016/02/12 11:28:52
forObject => fromObject (for consistency with from
keishi
2016/02/29 06:02:34
Done.
|
| +{ |
| + if (!object) |
| + return nullptr; |
| + BasePage* page = pageFromObject(object); |
| + ASSERT(page); |
| + ASSERT(page->heap()); |
| + return page->heap()->threadState(); |
| +} |
| + |
| } // namespace blink |