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 5dade81422fb90875c853471da1f73fa91d9e779..1f29cc5d064076ea44e6421ef2c92b10b9f00649 100644 |
| --- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp |
| +++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp |
| @@ -37,8 +37,10 @@ |
| #include "platform/heap/CallbackStack.h" |
| #include "platform/heap/Handle.h" |
| #include "platform/heap/Heap.h" |
| +#include "platform/heap/PagePool.h" |
| #include "platform/heap/MarkingVisitor.h" |
| #include "platform/heap/SafePoint.h" |
| +#include "platform/heap/PageMemory.h" |
| #include "public/platform/Platform.h" |
| #include "public/platform/WebMemoryAllocatorDump.h" |
| #include "public/platform/WebProcessMemoryDump.h" |
| @@ -68,6 +70,7 @@ extern "C" void* __libc_stack_end; // NOLINT |
| namespace blink { |
| WTF::ThreadSpecific<ThreadState*>* ThreadState::s_threadSpecific = nullptr; |
| +WTF::ThreadSpecific<ThreadState*>* ThreadState::s_threadSpecificTerminating = nullptr; |
| uintptr_t ThreadState::s_mainThreadStackStart = 0; |
| uintptr_t ThreadState::s_mainThreadUnderestimatedStackSize = 0; |
| uint8_t ThreadState::s_mainThreadStateStorage[sizeof(ThreadState)]; |
| @@ -81,7 +84,9 @@ RecursiveMutex& ThreadState::threadAttachMutex() |
| ThreadState::ThreadState() |
| : m_thread(currentThread()) |
| + , m_isolated(false) |
| , m_persistentRegion(adoptPtr(new PersistentRegion())) |
| + , m_xThreadPersistentRegion(adoptPtr(new XThreadPersistentRegion())) |
| #if OS(WIN) && COMPILER(MSVC) |
| , m_threadStackSize(0) |
| #endif |
| @@ -104,6 +109,26 @@ ThreadState::ThreadState() |
| #if defined(ADDRESS_SANITIZER) |
| , m_asanFakeStack(__asan_get_current_fake_stack()) |
| #endif |
| + , m_markingStack(adoptPtr(new CallbackStack())) |
| + , m_postMarkingCallbackStack(adoptPtr(new CallbackStack())) |
| + , m_globalWeakCallbackStack(adoptPtr(new CallbackStack())) |
| + , m_ephemeronStack(adoptPtr(new CallbackStack())) |
| + , m_freePagePool(adoptPtr(new FreePagePool())) |
| + , 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) |
| +#if ENABLE(ASSERT) |
| + , m_gcGeneration(1) |
| +#endif |
| + , m_heapDoesNotContainCache(adoptPtr(new HeapDoesNotContainCache())) |
| + , m_orphanedPagePool(adoptPtr(new OrphanedPagePool())) |
| + , m_regionTree(nullptr) |
| { |
| ASSERT(checkThread()); |
| ASSERT(!**s_threadSpecific); |
| @@ -139,11 +164,14 @@ ThreadState::~ThreadState() |
| s_mainThreadStackStart = 0; |
| s_mainThreadUnderestimatedStackSize = 0; |
| } |
| + ASSERT(!**s_threadSpecificTerminating); |
| + **s_threadSpecificTerminating = this; |
|
haraken
2015/11/30 02:54:42
I wonder why we need this.
keishi
2016/01/06 05:35:33
Removed
|
| } |
| void ThreadState::init() |
| { |
| s_threadSpecific = new WTF::ThreadSpecific<ThreadState*>(); |
| + s_threadSpecificTerminating = new WTF::ThreadSpecific<ThreadState*>(); |
| s_safePointBarrier = new SafePointBarrier; |
| } |
| @@ -192,7 +220,7 @@ size_t ThreadState::threadStackSize() |
| void ThreadState::attachMainThread() |
| { |
| - RELEASE_ASSERT(!Heap::s_shutdownCalled); |
| + //RELEASE_ASSERT(!m_shutdownCalled); |
| MutexLocker locker(threadAttachMutex()); |
| ThreadState* state = new(s_mainThreadStateStorage) ThreadState(); |
| attachedThreads().add(state); |
| @@ -226,17 +254,18 @@ void ThreadState::shutdownHeapIfNecessary() |
| { |
| // We don't need to enter a safe point before acquiring threadAttachMutex |
| // because this thread is already detached. |
| - |
| + ASSERT(!ThreadState::current() && ThreadState::terminating()); |
| 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) |
| + if (!attachedThreads().size()/* && ThreadState::terminating()->shutdownCalled()*/) |
| Heap::doShutdown(); |
| + //ThreadState::terminating()->setShutdownCalled(true); |
| } |
| void ThreadState::attach() |
| { |
| - RELEASE_ASSERT(!Heap::s_shutdownCalled); |
| + //RELEASE_ASSERT(!m_shutdownCalled); |
| MutexLocker locker(threadAttachMutex()); |
| ThreadState* state = new ThreadState(); |
| attachedThreads().add(state); |
| @@ -315,15 +344,19 @@ void ThreadState::visitPersistentRoots(Visitor* visitor) |
| TRACE_EVENT0("blink_gc", "ThreadState::visitPersistentRoots"); |
| crossThreadPersistentRegion().tracePersistentNodes(visitor); |
| - for (ThreadState* state : attachedThreads()) |
| - state->visitPersistents(visitor); |
| + for (ThreadState* state : attachedThreads()) { |
| + if (!state->isolated()) |
|
haraken
2015/11/30 02:54:42
As commented somewhere, I recommend you not add is
keishi
2016/01/06 05:35:33
Done.
|
| + state->visitPersistents(visitor); |
| + } |
| } |
| void ThreadState::visitStackRoots(Visitor* visitor) |
| { |
| TRACE_EVENT0("blink_gc", "ThreadState::visitStackRoots"); |
| - for (ThreadState* state : attachedThreads()) |
| - state->visitStack(visitor); |
| + for (ThreadState* state : attachedThreads()) { |
| + if (!state->isolated()) |
| + state->visitStack(visitor); |
| + } |
| } |
| NO_SANITIZE_ADDRESS |
| @@ -499,18 +532,18 @@ CrossThreadPersistentRegion& ThreadState::crossThreadPersistentRegion() |
| size_t ThreadState::totalMemorySize() |
| { |
| - return Heap::allocatedObjectSize() + Heap::markedObjectSize() + WTF::Partitions::totalSizeOfCommittedPages(); |
| + return allocatedObjectSize() + markedObjectSize() + WTF::Partitions::totalSizeOfCommittedPages(); |
| } |
| size_t ThreadState::estimatedLiveSize(size_t estimationBaseSize, size_t sizeAtLastGC) |
| { |
| - if (Heap::wrapperCountAtLastGC() == 0) { |
| + if (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 / wrapperCountAtLastGC() * collectedWrapperCount()); |
| if (estimationBaseSize < sizeRetainedByCollectedPersistents) |
| return 0; |
| return estimationBaseSize - sizeRetainedByCollectedPersistents; |
| @@ -518,8 +551,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 = allocatedObjectSize() + markedObjectSize(); |
| + size_t estimatedSize = estimatedLiveSize(markedObjectSizeAtLastCompleteSweep(), 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; |
| @@ -531,7 +564,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, 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; |
| @@ -545,7 +578,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 (allocatedObjectSize() < 100 * 1024 || totalMemorySize() < totalMemorySizeThreshold) |
| return false; |
| // If the growing rate of Oilpan's heap or PartitionAlloc is high enough, |
| // trigger a GC. |
| @@ -590,7 +623,7 @@ bool ThreadState::shouldForceMemoryPressureGC() |
| void ThreadState::scheduleV8FollowupGCIfNeeded(BlinkGC::V8GCType gcType) |
| { |
| ASSERT(checkThread()); |
| - Heap::reportMemoryUsageForTracing(); |
| + reportMemoryUsageForTracing(); |
| #if PRINT_HEAP_STATS |
| dataLogF("ThreadState::scheduleV8FollowupGCIfNeeded (gcType=%s)\n", gcType == BlinkGC::V8MajorGC ? "MajorGC" : "MinorGC"); |
| @@ -611,7 +644,10 @@ void ThreadState::scheduleV8FollowupGCIfNeeded(BlinkGC::V8GCType gcType) |
| #if PRINT_HEAP_STATS |
| dataLogF("Scheduled MemoryPressureGC\n"); |
| #endif |
| - Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithoutSweep, BlinkGC::MemoryPressureGC); |
| + if (isolated()) |
| + Heap::collectGarbageForIsolatedThread(this); |
|
haraken
2015/11/30 02:54:42
At the moment it is okay to ignore lazy sweeping (
keishi
2016/01/06 05:35:33
Done.
|
| + else |
| + Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithoutSweep, BlinkGC::MemoryPressureGC); |
| return; |
| } |
| if (shouldScheduleV8FollowupGC()) { |
| @@ -649,14 +685,17 @@ void ThreadState::willStartV8GC() |
| #if PRINT_HEAP_STATS |
| dataLogF("Scheduled PageNavigationGC\n"); |
| #endif |
| - Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithSweep, BlinkGC::PageNavigationGC); |
| + if (isolated()) |
| + Heap::collectGarbageForIsolatedThread(this); |
| + else |
| + Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithSweep, BlinkGC::PageNavigationGC); |
| } |
| } |
| void ThreadState::schedulePageNavigationGCIfNeeded(float estimatedRemovalRatio) |
| { |
| ASSERT(checkThread()); |
| - Heap::reportMemoryUsageForTracing(); |
| + reportMemoryUsageForTracing(); |
| #if PRINT_HEAP_STATS |
| dataLogF("ThreadState::schedulePageNavigationGCIfNeeded (estimatedRemovalRatio=%.2lf)\n", estimatedRemovalRatio); |
| @@ -698,7 +737,7 @@ void ThreadState::schedulePageNavigationGC() |
| void ThreadState::scheduleGCIfNeeded() |
| { |
| ASSERT(checkThread()); |
| - Heap::reportMemoryUsageForTracing(); |
| + reportMemoryUsageForTracing(); |
| #if PRINT_HEAP_STATS |
| dataLogF("ThreadState::scheduleGCIfNeeded\n"); |
| @@ -730,7 +769,10 @@ void ThreadState::scheduleGCIfNeeded() |
| #if PRINT_HEAP_STATS |
| dataLogF("Scheduled ConservativeGC\n"); |
| #endif |
| - Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithoutSweep, BlinkGC::ConservativeGC); |
| + if (isolated()) |
| + Heap::collectGarbageForIsolatedThread(this); |
| + else |
| + Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithoutSweep, BlinkGC::ConservativeGC); |
| return; |
| } |
| } |
| @@ -752,15 +794,18 @@ 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", estimatedMarkingTime()); |
| + if (idleDeltaInSeconds <= 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(); |
| return; |
| } |
| - Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithoutSweep, BlinkGC::IdleGC); |
| + if (isolated()) |
| + Heap::collectGarbageForIsolatedThread(this); |
| + else |
| + Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithoutSweep, BlinkGC::IdleGC); |
| } |
| void ThreadState::performIdleLazySweep(double deadlineSeconds) |
| @@ -934,10 +979,16 @@ void ThreadState::runScheduledGC(BlinkGC::StackState stackState) |
| Heap::collectAllGarbage(); |
| break; |
| case PreciseGCScheduled: |
| - Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithoutSweep, BlinkGC::PreciseGC); |
| + if (isolated()) |
| + Heap::collectGarbageForIsolatedThread(this); |
| + else |
| + Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithoutSweep, BlinkGC::PreciseGC); |
| break; |
| case PageNavigationGCScheduled: |
| - Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, BlinkGC::PageNavigationGC); |
| + if (isolated()) |
| + Heap::collectGarbageForIsolatedThread(this); |
| + else |
| + Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, BlinkGC::PageNavigationGC); |
| break; |
| case IdleGCScheduled: |
| // Idle time GC will be scheduled by Blink Scheduler. |
| @@ -950,7 +1001,7 @@ void ThreadState::runScheduledGC(BlinkGC::StackState stackState) |
| void ThreadState::flushHeapDoesNotContainCacheIfNeeded() |
| { |
| if (m_shouldFlushHeapDoesNotContainCache) { |
| - Heap::flushHeapDoesNotContainCache(); |
| + flushHeapDoesNotContainCache(); |
| m_shouldFlushHeapDoesNotContainCache = false; |
| } |
| } |
| @@ -1128,12 +1179,12 @@ void ThreadState::completeSweep() |
| void ThreadState::postSweep() |
| { |
| ASSERT(checkThread()); |
| - Heap::reportMemoryUsageForTracing(); |
| + reportMemoryUsageForTracing(); |
| if (isMainThread()) { |
| double collectionRate = 0; |
| - if (Heap::objectSizeAtLastGC() > 0) |
| - collectionRate = 1 - 1.0 * Heap::markedObjectSize() / Heap::objectSizeAtLastGC(); |
| + if (objectSizeAtLastGC() > 0) |
| + collectionRate = 1 - 1.0 * markedObjectSize() / objectSizeAtLastGC(); |
| TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadState::collectionRate", static_cast<int>(100 * collectionRate)); |
| #if PRINT_HEAP_STATS |
| @@ -1142,10 +1193,10 @@ void ThreadState::postSweep() |
| // Heap::markedObjectSize() may be underestimated here if any other |
| // thread has not yet finished lazy sweeping. |
| - Heap::setMarkedObjectSizeAtLastCompleteSweep(Heap::markedObjectSize()); |
| + setMarkedObjectSizeAtLastCompleteSweep(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", objectSizeAtLastGC() / 1024, 1, 4 * 1024 * 1024, 50); |
| + Platform::current()->histogramCustomCounts("BlinkGC.ObjectSizeAfterGC", 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); |
| } |
| @@ -1205,7 +1256,7 @@ void ThreadState::resumeThreads() |
| void ThreadState::safePoint(BlinkGC::StackState stackState) |
| { |
| ASSERT(checkThread()); |
| - Heap::reportMemoryUsageForTracing(); |
| + reportMemoryUsageForTracing(); |
| runScheduledGC(stackState); |
| ASSERT(!m_atSafePoint); |
| @@ -1489,4 +1540,139 @@ void ThreadState::takeSnapshot(SnapshotType type) |
| BlinkGCMemoryDumpProvider::instance()->currentProcessMemoryDump()->addOwnershipEdge(classesDump->guid(), heapsDump->guid()); |
| } |
| +double ThreadState::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 ThreadState::reportMemoryUsageHistogram() |
| +{ |
| + static size_t supportedMaxSizeInMB = 4 * 1024; |
| + static size_t observedMaxSizeInMB = 0; |
| + |
| + // FIXME: Separate report per thread |
| + |
| + // +1 is for rounding up the sizeInMB. |
| + size_t sizeInMB = allocatedSpace() / 1024 / 1024 + 1; |
| + if (sizeInMB >= supportedMaxSizeInMB) |
| + sizeInMB = supportedMaxSizeInMB - 1; |
| + if (sizeInMB > observedMaxSizeInMB) { |
| + // Send a UseCounter only when we see the highest memory usage |
| + // we've ever seen. |
| + Platform::current()->histogramEnumeration("BlinkGC.CommittedSize", sizeInMB, supportedMaxSizeInMB); |
| + observedMaxSizeInMB = sizeInMB; |
| + } |
| +} |
| + |
| +void ThreadState::reportMemoryUsageForTracing() |
| +{ |
| + // FIXME: Separate report per thread |
| +#if PRINT_HEAP_STATS |
| + // dataLogF("allocatedSpace=%ldMB, allocatedObjectSize=%ldMB, markedObjectSize=%ldMB, partitionAllocSize=%ldMB, wrapperCount=%ld, collectedWrapperCount=%ld\n", Heap::allocatedSpace() / 1024 / 1024, Heap::allocatedObjectSize() / 1024 / 1024, Heap::markedObjectSize() / 1024 / 1024, WTF::Partitions::totalSizeOfCommittedPages() / 1024 / 1024, Heap::wrapperCount(), Heap::collectedWrapperCount()); |
| +#endif |
| + |
| + bool gcTracingEnabled; |
| + TRACE_EVENT_CATEGORY_GROUP_ENABLED("blink_gc", &gcTracingEnabled); |
| + if (!gcTracingEnabled) |
| + return; |
| + |
| + // These values are divided by 1024 to avoid overflow in practical cases (TRACE_COUNTER values are 32-bit ints). |
| + // They are capped to INT_MAX just in case. |
| + TRACE_COUNTER1("blink_gc", "Heap::allocatedObjectSizeKB", std::min(allocatedObjectSize() / 1024, static_cast<size_t>(INT_MAX))); |
| + TRACE_COUNTER1("blink_gc", "Heap::markedObjectSizeKB", std::min(markedObjectSize() / 1024, static_cast<size_t>(INT_MAX))); |
| + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "Heap::markedObjectSizeAtLastCompleteSweepKB", std::min(markedObjectSizeAtLastCompleteSweep() / 1024, static_cast<size_t>(INT_MAX))); |
| + TRACE_COUNTER1("blink_gc", "Heap::allocatedSpaceKB", std::min(allocatedSpace() / 1024, static_cast<size_t>(INT_MAX))); |
| + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "Heap::objectSizeAtLastGCKB", std::min(objectSizeAtLastGC() / 1024, static_cast<size_t>(INT_MAX))); |
| + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "Heap::wrapperCount", std::min(wrapperCount(), static_cast<size_t>(INT_MAX))); |
| + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "Heap::wrapperCountAtLastGC", std::min(wrapperCountAtLastGC(), static_cast<size_t>(INT_MAX))); |
| + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "Heap::collectedWrapperCount", std::min(collectedWrapperCount(), static_cast<size_t>(INT_MAX))); |
| + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "Heap::partitionAllocSizeAtLastGCKB", std::min(partitionAllocSizeAtLastGC() / 1024, static_cast<size_t>(INT_MAX))); |
| + TRACE_COUNTER1("blink_gc", "Partitions::totalSizeOfCommittedPagesKB", std::min(WTF::Partitions::totalSizeOfCommittedPages() / 1024, static_cast<size_t>(INT_MAX))); |
| +} |
| + |
| +void ThreadState::resetHeapCounters() |
| +{ |
| + ASSERT(isInGC()); |
| + |
| + reportMemoryUsageForTracing(); |
| + |
| + m_objectSizeAtLastGC = m_allocatedObjectSize + m_markedObjectSize; |
| + m_partitionAllocSizeAtLastGC = WTF::Partitions::totalSizeOfCommittedPages(); |
| + m_allocatedObjectSize = 0; |
| + m_markedObjectSize = 0; |
| + m_wrapperCountAtLastGC = m_wrapperCount; |
| + m_collectedWrapperCount = 0; |
| +} |
| + |
| +void ThreadState::flushHeapDoesNotContainCache() |
| +{ |
| + m_heapDoesNotContainCache->flush(); |
| +} |
| + |
| +PageMemoryRegion* ThreadState::RegionTree::lookup(Address address) |
| +{ |
| + RegionTree* current = ThreadState::current()->regionTree(); |
| + while (current) { |
| + Address base = current->m_region->base(); |
| + if (address < base) { |
| + current = current->m_left; |
| + continue; |
| + } |
| + if (address >= base + current->m_region->size()) { |
| + current = current->m_right; |
| + continue; |
| + } |
| + ASSERT(current->m_region->contains(address)); |
| + return current->m_region; |
| + } |
| + return nullptr; |
| +} |
| + |
| +void ThreadState::RegionTree::add(RegionTree* newTree, RegionTree** context) |
| +{ |
| + ASSERT(newTree); |
| + Address base = newTree->m_region->base(); |
| + for (RegionTree* current = *context; current; current = *context) { |
| + ASSERT(!current->m_region->contains(base)); |
| + context = (base < current->m_region->base()) ? ¤t->m_left : ¤t->m_right; |
| + } |
| + *context = newTree; |
| +} |
| + |
| +void ThreadState::RegionTree::remove(PageMemoryRegion* region, RegionTree** context) |
| +{ |
| + ASSERT(region); |
| + ASSERT(context); |
| + Address base = region->base(); |
| + RegionTree* current = *context; |
| + for (; current; current = *context) { |
| + if (region == current->m_region) |
| + break; |
| + context = (base < current->m_region->base()) ? ¤t->m_left : ¤t->m_right; |
| + } |
| + |
| + // Shutdown via detachMainThread might not have populated the region tree. |
| + if (!current) |
| + return; |
| + |
| + *context = nullptr; |
| + if (current->m_left) { |
| + add(current->m_left, context); |
| + current->m_left = nullptr; |
| + } |
| + if (current->m_right) { |
| + add(current->m_right, context); |
| + current->m_right = nullptr; |
| + } |
| + delete current; |
| +} |
| + |
| } // namespace blink |