| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 51 #include "wtf/allocator/Partitions.h" | 51 #include "wtf/allocator/Partitions.h" |
| 52 | 52 |
| 53 namespace blink { | 53 namespace blink { |
| 54 | 54 |
| 55 HeapAllocHooks::AllocationHook* HeapAllocHooks::m_allocationHook = nullptr; | 55 HeapAllocHooks::AllocationHook* HeapAllocHooks::m_allocationHook = nullptr; |
| 56 HeapAllocHooks::FreeHook* HeapAllocHooks::m_freeHook = nullptr; | 56 HeapAllocHooks::FreeHook* HeapAllocHooks::m_freeHook = nullptr; |
| 57 | 57 |
| 58 class ParkThreadsScope final { | 58 class ParkThreadsScope final { |
| 59 STACK_ALLOCATED(); | 59 STACK_ALLOCATED(); |
| 60 public: | 60 public: |
| 61 explicit ParkThreadsScope(ThreadState* state) | 61 ParkThreadsScope() |
| 62 : m_state(state) | 62 : m_shouldResumeThreads(false) |
| 63 , m_shouldResumeThreads(false) | |
| 64 { | 63 { |
| 65 } | 64 } |
| 66 | 65 |
| 67 bool parkThreads() | 66 bool parkThreads(ThreadState* state) |
| 68 { | 67 { |
| 69 TRACE_EVENT0("blink_gc", "ThreadHeap::ParkThreadsScope"); | 68 TRACE_EVENT0("blink_gc", "ThreadHeap::ParkThreadsScope"); |
| 70 const char* samplingState = TRACE_EVENT_GET_SAMPLING_STATE(); | 69 const char* samplingState = TRACE_EVENT_GET_SAMPLING_STATE(); |
| 71 if (m_state->isMainThread()) | 70 if (state->isMainThread()) |
| 72 TRACE_EVENT_SET_SAMPLING_STATE("blink_gc", "BlinkGCWaiting"); | 71 TRACE_EVENT_SET_SAMPLING_STATE("blink_gc", "BlinkGCWaiting"); |
| 73 | 72 |
| 74 // TODO(haraken): In an unlikely coincidence that two threads decide | 73 // TODO(haraken): In an unlikely coincidence that two threads decide |
| 75 // to collect garbage at the same time, avoid doing two GCs in | 74 // to collect garbage at the same time, avoid doing two GCs in |
| 76 // a row and return false. | 75 // a row and return false. |
| 77 double startTime = WTF::currentTimeMS(); | 76 double startTime = WTF::currentTimeMS(); |
| 78 | 77 |
| 79 m_shouldResumeThreads = m_state->heap().park(); | 78 m_shouldResumeThreads = ThreadState::stopThreads(); |
| 80 | 79 |
| 81 double timeForStoppingThreads = WTF::currentTimeMS() - startTime; | 80 double timeForStoppingThreads = WTF::currentTimeMS() - startTime; |
| 82 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, timeToStopThreadsH
istogram, new CustomCountHistogram("BlinkGC.TimeForStoppingThreads", 1, 1000, 50
)); | 81 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, timeToStopThreadsH
istogram, new CustomCountHistogram("BlinkGC.TimeForStoppingThreads", 1, 1000, 50
)); |
| 83 timeToStopThreadsHistogram.count(timeForStoppingThreads); | 82 timeToStopThreadsHistogram.count(timeForStoppingThreads); |
| 84 | 83 |
| 85 if (m_state->isMainThread()) | 84 if (state->isMainThread()) |
| 86 TRACE_EVENT_SET_NONCONST_SAMPLING_STATE(samplingState); | 85 TRACE_EVENT_SET_NONCONST_SAMPLING_STATE(samplingState); |
| 87 return m_shouldResumeThreads; | 86 return m_shouldResumeThreads; |
| 88 } | 87 } |
| 89 | 88 |
| 90 ~ParkThreadsScope() | 89 ~ParkThreadsScope() |
| 91 { | 90 { |
| 92 // Only cleanup if we parked all threads in which case the GC happened | 91 // Only cleanup if we parked all threads in which case the GC happened |
| 93 // and we need to resume the other threads. | 92 // and we need to resume the other threads. |
| 94 if (m_shouldResumeThreads) | 93 if (m_shouldResumeThreads) |
| 95 m_state->heap().resume(); | 94 ThreadState::resumeThreads(); |
| 96 } | 95 } |
| 97 | 96 |
| 98 private: | 97 private: |
| 99 ThreadState* m_state; | |
| 100 bool m_shouldResumeThreads; | 98 bool m_shouldResumeThreads; |
| 101 }; | 99 }; |
| 102 | 100 |
| 103 void ThreadHeap::flushHeapDoesNotContainCache() | 101 void ThreadHeap::flushHeapDoesNotContainCache() |
| 104 { | 102 { |
| 105 m_heapDoesNotContainCache->flush(); | 103 s_heapDoesNotContainCache->flush(); |
| 106 } | 104 } |
| 107 | 105 |
| 108 void ProcessHeap::init() | 106 void ProcessHeap::init() |
| 109 { | 107 { |
| 110 s_shutdownComplete = false; | |
| 111 s_totalAllocatedSpace = 0; | 108 s_totalAllocatedSpace = 0; |
| 112 s_totalAllocatedObjectSize = 0; | 109 s_totalAllocatedObjectSize = 0; |
| 113 s_totalMarkedObjectSize = 0; | 110 s_totalMarkedObjectSize = 0; |
| 114 s_isLowEndDevice = base::SysInfo::IsLowEndDevice(); | 111 s_isLowEndDevice = base::SysInfo::IsLowEndDevice(); |
| 115 | |
| 116 GCInfoTable::init(); | |
| 117 | |
| 118 if (Platform::current() && Platform::current()->currentThread()) | |
| 119 Platform::current()->registerMemoryDumpProvider(BlinkGCMemoryDumpProvide
r::instance(), "BlinkGC"); | |
| 120 } | 112 } |
| 121 | 113 |
| 122 void ProcessHeap::resetHeapCounters() | 114 void ProcessHeap::resetHeapCounters() |
| 123 { | 115 { |
| 124 s_totalAllocatedObjectSize = 0; | 116 s_totalAllocatedObjectSize = 0; |
| 125 s_totalMarkedObjectSize = 0; | 117 s_totalMarkedObjectSize = 0; |
| 126 } | 118 } |
| 127 | 119 |
| 128 void ProcessHeap::shutdown() | 120 void ThreadHeap::init() |
| 129 { | 121 { |
| 130 ASSERT(!s_shutdownComplete); | 122 ThreadState::init(); |
| 123 ProcessHeap::init(); |
| 124 s_markingStack = new CallbackStack(); |
| 125 s_postMarkingCallbackStack = new CallbackStack(); |
| 126 s_globalWeakCallbackStack = new CallbackStack(); |
| 127 // Use smallest supported block size for ephemerons. |
| 128 s_ephemeronStack = new CallbackStack(CallbackStack::kMinimalBlockSize); |
| 129 s_heapDoesNotContainCache = new HeapDoesNotContainCache(); |
| 130 s_freePagePool = new FreePagePool(); |
| 131 s_orphanedPagePool = new OrphanedPagePool(); |
| 132 s_lastGCReason = BlinkGC::NumberOfGCReason; |
| 133 |
| 134 GCInfoTable::init(); |
| 135 |
| 136 if (Platform::current() && Platform::current()->currentThread()) |
| 137 Platform::current()->registerMemoryDumpProvider(BlinkGCMemoryDumpProvide
r::instance(), "BlinkGC"); |
| 138 } |
| 139 |
| 140 void ThreadHeap::shutdown() |
| 141 { |
| 142 ASSERT(s_markingStack); |
| 131 | 143 |
| 132 if (Platform::current() && Platform::current()->currentThread()) | 144 if (Platform::current() && Platform::current()->currentThread()) |
| 133 Platform::current()->unregisterMemoryDumpProvider(BlinkGCMemoryDumpProvi
der::instance()); | 145 Platform::current()->unregisterMemoryDumpProvider(BlinkGCMemoryDumpProvi
der::instance()); |
| 134 | 146 |
| 135 { | 147 // The main thread must be the last thread that gets detached. |
| 136 // The main thread must be the last thread that gets detached. | 148 RELEASE_ASSERT(ThreadState::attachedThreads().size() == 0); |
| 137 MutexLocker locker(ThreadHeap::allHeapsMutex()); | |
| 138 RELEASE_ASSERT(ThreadHeap::allHeaps().isEmpty()); | |
| 139 } | |
| 140 | 149 |
| 150 delete s_heapDoesNotContainCache; |
| 151 s_heapDoesNotContainCache = nullptr; |
| 152 delete s_freePagePool; |
| 153 s_freePagePool = nullptr; |
| 154 delete s_orphanedPagePool; |
| 155 s_orphanedPagePool = nullptr; |
| 156 delete s_globalWeakCallbackStack; |
| 157 s_globalWeakCallbackStack = nullptr; |
| 158 delete s_postMarkingCallbackStack; |
| 159 s_postMarkingCallbackStack = nullptr; |
| 160 delete s_markingStack; |
| 161 s_markingStack = nullptr; |
| 162 delete s_ephemeronStack; |
| 163 s_ephemeronStack = nullptr; |
| 141 GCInfoTable::shutdown(); | 164 GCInfoTable::shutdown(); |
| 142 ASSERT(ProcessHeap::totalAllocatedSpace() == 0); | 165 ThreadState::shutdown(); |
| 143 s_shutdownComplete = true; | 166 ASSERT(ThreadHeap::heapStats().allocatedSpace() == 0); |
| 144 } | 167 } |
| 145 | 168 |
| 146 CrossThreadPersistentRegion& ProcessHeap::crossThreadPersistentRegion() | 169 CrossThreadPersistentRegion& ProcessHeap::crossThreadPersistentRegion() |
| 147 { | 170 { |
| 148 DEFINE_THREAD_SAFE_STATIC_LOCAL(CrossThreadPersistentRegion, persistentRegio
n, new CrossThreadPersistentRegion()); | 171 DEFINE_THREAD_SAFE_STATIC_LOCAL(CrossThreadPersistentRegion, persistentRegio
n, new CrossThreadPersistentRegion()); |
| 149 return persistentRegion; | 172 return persistentRegion; |
| 150 } | 173 } |
| 151 | 174 |
| 152 bool ProcessHeap::s_shutdownComplete = false; | |
| 153 bool ProcessHeap::s_isLowEndDevice = false; | 175 bool ProcessHeap::s_isLowEndDevice = false; |
| 154 size_t ProcessHeap::s_totalAllocatedSpace = 0; | 176 size_t ProcessHeap::s_totalAllocatedSpace = 0; |
| 155 size_t ProcessHeap::s_totalAllocatedObjectSize = 0; | 177 size_t ProcessHeap::s_totalAllocatedObjectSize = 0; |
| 156 size_t ProcessHeap::s_totalMarkedObjectSize = 0; | 178 size_t ProcessHeap::s_totalMarkedObjectSize = 0; |
| 157 | 179 |
| 158 ThreadHeapStats::ThreadHeapStats() | 180 ThreadHeapStats::ThreadHeapStats() |
| 159 : m_allocatedSpace(0) | 181 : m_allocatedSpace(0) |
| 160 , m_allocatedObjectSize(0) | 182 , m_allocatedObjectSize(0) |
| 161 , m_objectSizeAtLastGC(0) | 183 , m_objectSizeAtLastGC(0) |
| 162 , m_markedObjectSize(0) | 184 , m_markedObjectSize(0) |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 215 atomicAdd(&m_allocatedSpace, static_cast<long>(delta)); | 237 atomicAdd(&m_allocatedSpace, static_cast<long>(delta)); |
| 216 ProcessHeap::increaseTotalAllocatedSpace(delta); | 238 ProcessHeap::increaseTotalAllocatedSpace(delta); |
| 217 } | 239 } |
| 218 | 240 |
| 219 void ThreadHeapStats::decreaseAllocatedSpace(size_t delta) | 241 void ThreadHeapStats::decreaseAllocatedSpace(size_t delta) |
| 220 { | 242 { |
| 221 atomicSubtract(&m_allocatedSpace, static_cast<long>(delta)); | 243 atomicSubtract(&m_allocatedSpace, static_cast<long>(delta)); |
| 222 ProcessHeap::decreaseTotalAllocatedSpace(delta); | 244 ProcessHeap::decreaseTotalAllocatedSpace(delta); |
| 223 } | 245 } |
| 224 | 246 |
| 225 ThreadHeap::ThreadHeap() | |
| 226 : m_regionTree(adoptPtr(new RegionTree())) | |
| 227 , m_heapDoesNotContainCache(adoptPtr(new HeapDoesNotContainCache)) | |
| 228 , m_safePointBarrier(adoptPtr(new SafePointBarrier())) | |
| 229 , m_freePagePool(adoptPtr(new FreePagePool)) | |
| 230 , m_orphanedPagePool(adoptPtr(new OrphanedPagePool)) | |
| 231 , m_markingStack(adoptPtr(new CallbackStack())) | |
| 232 , m_postMarkingCallbackStack(adoptPtr(new CallbackStack())) | |
| 233 , m_globalWeakCallbackStack(adoptPtr(new CallbackStack())) | |
| 234 , m_ephemeronStack(adoptPtr(new CallbackStack(CallbackStack::kMinimalBlockSi
ze))) | |
| 235 { | |
| 236 if (ThreadState::current()->isMainThread()) | |
| 237 s_mainThreadHeap = this; | |
| 238 | |
| 239 MutexLocker locker(ThreadHeap::allHeapsMutex()); | |
| 240 allHeaps().add(this); | |
| 241 } | |
| 242 | |
| 243 ThreadHeap::~ThreadHeap() | |
| 244 { | |
| 245 MutexLocker locker(ThreadHeap::allHeapsMutex()); | |
| 246 allHeaps().remove(this); | |
| 247 } | |
| 248 | |
| 249 RecursiveMutex& ThreadHeap::allHeapsMutex() | |
| 250 { | |
| 251 DEFINE_THREAD_SAFE_STATIC_LOCAL(RecursiveMutex, mutex, (new RecursiveMutex))
; | |
| 252 return mutex; | |
| 253 } | |
| 254 | |
| 255 HashSet<ThreadHeap*>& ThreadHeap::allHeaps() | |
| 256 { | |
| 257 DEFINE_STATIC_LOCAL(HashSet<ThreadHeap*>, heaps, ()); | |
| 258 return heaps; | |
| 259 } | |
| 260 | |
| 261 void ThreadHeap::attach(ThreadState* thread) | |
| 262 { | |
| 263 MutexLocker locker(m_threadAttachMutex); | |
| 264 m_threads.add(thread); | |
| 265 } | |
| 266 | |
| 267 void ThreadHeap::detach(ThreadState* thread) | |
| 268 { | |
| 269 ASSERT(ThreadState::current() == thread); | |
| 270 { | |
| 271 // Grab the threadAttachMutex to ensure only one thread can shutdown at | |
| 272 // a time and that no other thread can do a global GC. It also allows | |
| 273 // safe iteration of the m_threads set which happens as part of | |
| 274 // thread local GC asserts. We enter a safepoint while waiting for the | |
| 275 // lock to avoid a dead-lock where another thread has already requested | |
| 276 // GC. | |
| 277 SafePointAwareMutexLocker locker(m_threadAttachMutex, BlinkGC::NoHeapPoi
ntersOnStack); | |
| 278 thread->runTerminationGC(); | |
| 279 ASSERT(m_threads.contains(thread)); | |
| 280 m_threads.remove(thread); | |
| 281 } | |
| 282 // The main thread must be the last thread that gets detached. | |
| 283 ASSERT(!thread->isMainThread() || m_threads.isEmpty()); | |
| 284 if (thread->isMainThread()) { | |
| 285 ASSERT(heapStats().allocatedSpace() == 0); | |
| 286 delete this; | |
| 287 } | |
| 288 } | |
| 289 | |
| 290 bool ThreadHeap::park() | |
| 291 { | |
| 292 return m_safePointBarrier->parkOthers(); | |
| 293 } | |
| 294 | |
| 295 void ThreadHeap::resume() | |
| 296 { | |
| 297 m_safePointBarrier->resumeOthers(); | |
| 298 } | |
| 299 | |
| 300 #if ENABLE(ASSERT) | 247 #if ENABLE(ASSERT) |
| 301 BasePage* ThreadHeap::findPageFromAddress(Address address) | 248 BasePage* ThreadHeap::findPageFromAddress(Address address) |
| 302 { | 249 { |
| 303 MutexLocker locker(m_threadAttachMutex); | 250 MutexLocker lock(ThreadState::threadAttachMutex()); |
| 304 for (ThreadState* state : m_threads) { | 251 for (ThreadState* state : ThreadState::attachedThreads()) { |
| 305 if (BasePage* page = state->findPageFromAddress(address)) | 252 if (BasePage* page = state->findPageFromAddress(address)) |
| 306 return page; | 253 return page; |
| 307 } | 254 } |
| 308 return nullptr; | 255 return nullptr; |
| 309 } | 256 } |
| 310 | |
| 311 bool ThreadHeap::isAtSafePoint() | |
| 312 { | |
| 313 MutexLocker locker(m_threadAttachMutex); | |
| 314 for (ThreadState* state : m_threads) { | |
| 315 if (!state->isAtSafePoint()) | |
| 316 return false; | |
| 317 } | |
| 318 return true; | |
| 319 } | |
| 320 #endif | 257 #endif |
| 321 | 258 |
| 322 Address ThreadHeap::checkAndMarkPointer(Visitor* visitor, Address address) | 259 Address ThreadHeap::checkAndMarkPointer(Visitor* visitor, Address address) |
| 323 { | 260 { |
| 324 ASSERT(ThreadState::current()->isInGC()); | 261 ASSERT(ThreadState::current()->isInGC()); |
| 325 | 262 |
| 326 #if !ENABLE(ASSERT) | 263 #if !ENABLE(ASSERT) |
| 327 if (m_heapDoesNotContainCache->lookup(address)) | 264 if (s_heapDoesNotContainCache->lookup(address)) |
| 328 return nullptr; | 265 return nullptr; |
| 329 #endif | 266 #endif |
| 330 | 267 |
| 331 if (BasePage* page = lookupPageForAddress(address)) { | 268 if (BasePage* page = lookup(address)) { |
| 332 ASSERT(page->contains(address)); | 269 ASSERT(page->contains(address)); |
| 333 ASSERT(!page->orphaned()); | 270 ASSERT(!page->orphaned()); |
| 334 ASSERT(!m_heapDoesNotContainCache->lookup(address)); | 271 ASSERT(!s_heapDoesNotContainCache->lookup(address)); |
| 335 page->checkAndMarkPointer(visitor, address); | 272 page->checkAndMarkPointer(visitor, address); |
| 336 return address; | 273 return address; |
| 337 } | 274 } |
| 338 | 275 |
| 339 #if !ENABLE(ASSERT) | 276 #if !ENABLE(ASSERT) |
| 340 m_heapDoesNotContainCache->addEntry(address); | 277 s_heapDoesNotContainCache->addEntry(address); |
| 341 #else | 278 #else |
| 342 if (!m_heapDoesNotContainCache->lookup(address)) | 279 if (!s_heapDoesNotContainCache->lookup(address)) |
| 343 m_heapDoesNotContainCache->addEntry(address); | 280 s_heapDoesNotContainCache->addEntry(address); |
| 344 #endif | 281 #endif |
| 345 return nullptr; | 282 return nullptr; |
| 346 } | 283 } |
| 347 | 284 |
| 348 void ThreadHeap::pushTraceCallback(void* object, TraceCallback callback) | 285 void ThreadHeap::pushTraceCallback(void* object, TraceCallback callback) |
| 349 { | 286 { |
| 350 ASSERT(ThreadState::current()->isInGC()); | 287 ASSERT(ThreadState::current()->isInGC()); |
| 351 | 288 |
| 352 // Trace should never reach an orphaned page. | 289 // Trace should never reach an orphaned page. |
| 353 ASSERT(!getOrphanedPagePool()->contains(object)); | 290 ASSERT(!ThreadHeap::getOrphanedPagePool()->contains(object)); |
| 354 CallbackStack::Item* slot = m_markingStack->allocateEntry(); | 291 CallbackStack::Item* slot = s_markingStack->allocateEntry(); |
| 355 *slot = CallbackStack::Item(object, callback); | 292 *slot = CallbackStack::Item(object, callback); |
| 356 } | 293 } |
| 357 | 294 |
| 358 bool ThreadHeap::popAndInvokeTraceCallback(Visitor* visitor) | 295 bool ThreadHeap::popAndInvokeTraceCallback(Visitor* visitor) |
| 359 { | 296 { |
| 360 CallbackStack::Item* item = m_markingStack->pop(); | 297 CallbackStack::Item* item = s_markingStack->pop(); |
| 361 if (!item) | 298 if (!item) |
| 362 return false; | 299 return false; |
| 363 item->call(visitor); | 300 item->call(visitor); |
| 364 return true; | 301 return true; |
| 365 } | 302 } |
| 366 | 303 |
| 367 void ThreadHeap::pushPostMarkingCallback(void* object, TraceCallback callback) | 304 void ThreadHeap::pushPostMarkingCallback(void* object, TraceCallback callback) |
| 368 { | 305 { |
| 369 ASSERT(ThreadState::current()->isInGC()); | 306 ASSERT(ThreadState::current()->isInGC()); |
| 370 | 307 |
| 371 // Trace should never reach an orphaned page. | 308 // Trace should never reach an orphaned page. |
| 372 ASSERT(!getOrphanedPagePool()->contains(object)); | 309 ASSERT(!ThreadHeap::getOrphanedPagePool()->contains(object)); |
| 373 CallbackStack::Item* slot = m_postMarkingCallbackStack->allocateEntry(); | 310 CallbackStack::Item* slot = s_postMarkingCallbackStack->allocateEntry(); |
| 374 *slot = CallbackStack::Item(object, callback); | 311 *slot = CallbackStack::Item(object, callback); |
| 375 } | 312 } |
| 376 | 313 |
| 377 bool ThreadHeap::popAndInvokePostMarkingCallback(Visitor* visitor) | 314 bool ThreadHeap::popAndInvokePostMarkingCallback(Visitor* visitor) |
| 378 { | 315 { |
| 379 if (CallbackStack::Item* item = m_postMarkingCallbackStack->pop()) { | 316 if (CallbackStack::Item* item = s_postMarkingCallbackStack->pop()) { |
| 380 item->call(visitor); | 317 item->call(visitor); |
| 381 return true; | 318 return true; |
| 382 } | 319 } |
| 383 return false; | 320 return false; |
| 384 } | 321 } |
| 385 | 322 |
| 386 void ThreadHeap::pushGlobalWeakCallback(void** cell, WeakCallback callback) | 323 void ThreadHeap::pushGlobalWeakCallback(void** cell, WeakCallback callback) |
| 387 { | 324 { |
| 388 ASSERT(ThreadState::current()->isInGC()); | 325 ASSERT(ThreadState::current()->isInGC()); |
| 389 | 326 |
| 390 // Trace should never reach an orphaned page. | 327 // Trace should never reach an orphaned page. |
| 391 ASSERT(!getOrphanedPagePool()->contains(cell)); | 328 ASSERT(!ThreadHeap::getOrphanedPagePool()->contains(cell)); |
| 392 CallbackStack::Item* slot = m_globalWeakCallbackStack->allocateEntry(); | 329 CallbackStack::Item* slot = s_globalWeakCallbackStack->allocateEntry(); |
| 393 *slot = CallbackStack::Item(cell, callback); | 330 *slot = CallbackStack::Item(cell, callback); |
| 394 } | 331 } |
| 395 | 332 |
| 396 void ThreadHeap::pushThreadLocalWeakCallback(void* closure, void* object, WeakCa
llback callback) | 333 void ThreadHeap::pushThreadLocalWeakCallback(void* closure, void* object, WeakCa
llback callback) |
| 397 { | 334 { |
| 398 ASSERT(ThreadState::current()->isInGC()); | 335 ASSERT(ThreadState::current()->isInGC()); |
| 399 | 336 |
| 400 // Trace should never reach an orphaned page. | 337 // Trace should never reach an orphaned page. |
| 401 ASSERT(!getOrphanedPagePool()->contains(object)); | 338 ASSERT(!ThreadHeap::getOrphanedPagePool()->contains(object)); |
| 402 ThreadState* state = pageFromObject(object)->arena()->getThreadState(); | 339 ThreadState* state = pageFromObject(object)->arena()->getThreadState(); |
| 403 state->pushThreadLocalWeakCallback(closure, callback); | 340 state->pushThreadLocalWeakCallback(closure, callback); |
| 404 } | 341 } |
| 405 | 342 |
| 406 bool ThreadHeap::popAndInvokeGlobalWeakCallback(Visitor* visitor) | 343 bool ThreadHeap::popAndInvokeGlobalWeakCallback(Visitor* visitor) |
| 407 { | 344 { |
| 408 if (CallbackStack::Item* item = m_globalWeakCallbackStack->pop()) { | 345 if (CallbackStack::Item* item = s_globalWeakCallbackStack->pop()) { |
| 409 item->call(visitor); | 346 item->call(visitor); |
| 410 return true; | 347 return true; |
| 411 } | 348 } |
| 412 return false; | 349 return false; |
| 413 } | 350 } |
| 414 | 351 |
| 415 void ThreadHeap::registerWeakTable(void* table, EphemeronCallback iterationCallb
ack, EphemeronCallback iterationDoneCallback) | 352 void ThreadHeap::registerWeakTable(void* table, EphemeronCallback iterationCallb
ack, EphemeronCallback iterationDoneCallback) |
| 416 { | 353 { |
| 417 ASSERT(ThreadState::current()->isInGC()); | 354 ASSERT(ThreadState::current()->isInGC()); |
| 418 | 355 |
| 419 // Trace should never reach an orphaned page. | 356 // Trace should never reach an orphaned page. |
| 420 ASSERT(!getOrphanedPagePool()->contains(table)); | 357 ASSERT(!ThreadHeap::getOrphanedPagePool()->contains(table)); |
| 421 CallbackStack::Item* slot = m_ephemeronStack->allocateEntry(); | 358 CallbackStack::Item* slot = s_ephemeronStack->allocateEntry(); |
| 422 *slot = CallbackStack::Item(table, iterationCallback); | 359 *slot = CallbackStack::Item(table, iterationCallback); |
| 423 | 360 |
| 424 // Register a post-marking callback to tell the tables that | 361 // Register a post-marking callback to tell the tables that |
| 425 // ephemeron iteration is complete. | 362 // ephemeron iteration is complete. |
| 426 pushPostMarkingCallback(table, iterationDoneCallback); | 363 pushPostMarkingCallback(table, iterationDoneCallback); |
| 427 } | 364 } |
| 428 | 365 |
| 429 #if ENABLE(ASSERT) | 366 #if ENABLE(ASSERT) |
| 430 bool ThreadHeap::weakTableRegistered(const void* table) | 367 bool ThreadHeap::weakTableRegistered(const void* table) |
| 431 { | 368 { |
| 432 ASSERT(m_ephemeronStack); | 369 ASSERT(s_ephemeronStack); |
| 433 return m_ephemeronStack->hasCallbackForObject(table); | 370 return s_ephemeronStack->hasCallbackForObject(table); |
| 434 } | 371 } |
| 435 #endif | 372 #endif |
| 436 | 373 |
| 437 void ThreadHeap::decommitCallbackStacks() | 374 void ThreadHeap::decommitCallbackStacks() |
| 438 { | 375 { |
| 439 m_markingStack->decommit(); | 376 s_markingStack->decommit(); |
| 440 m_postMarkingCallbackStack->decommit(); | 377 s_postMarkingCallbackStack->decommit(); |
| 441 m_globalWeakCallbackStack->decommit(); | 378 s_globalWeakCallbackStack->decommit(); |
| 442 m_ephemeronStack->decommit(); | 379 s_ephemeronStack->decommit(); |
| 443 } | 380 } |
| 444 | 381 |
| 445 void ThreadHeap::preGC() | 382 void ThreadHeap::preGC() |
| 446 { | 383 { |
| 447 ASSERT(!ThreadState::current()->isInGC()); | 384 ASSERT(!ThreadState::current()->isInGC()); |
| 448 for (ThreadState* state : m_threads) { | 385 for (ThreadState* state : ThreadState::attachedThreads()) |
| 449 state->preGC(); | 386 state->preGC(); |
| 450 } | |
| 451 } | 387 } |
| 452 | 388 |
| 453 void ThreadHeap::postGC(BlinkGC::GCType gcType) | 389 void ThreadHeap::postGC(BlinkGC::GCType gcType) |
| 454 { | 390 { |
| 455 ASSERT(ThreadState::current()->isInGC()); | 391 ASSERT(ThreadState::current()->isInGC()); |
| 456 for (ThreadState* state : m_threads) { | 392 for (ThreadState* state : ThreadState::attachedThreads()) |
| 457 state->postGC(gcType); | 393 state->postGC(gcType); |
| 458 } | |
| 459 } | 394 } |
| 460 | 395 |
| 461 const char* ThreadHeap::gcReasonString(BlinkGC::GCReason reason) | 396 const char* ThreadHeap::gcReasonString(BlinkGC::GCReason reason) |
| 462 { | 397 { |
| 463 switch (reason) { | 398 switch (reason) { |
| 464 case BlinkGC::IdleGC: | 399 case BlinkGC::IdleGC: |
| 465 return "IdleGC"; | 400 return "IdleGC"; |
| 466 case BlinkGC::PreciseGC: | 401 case BlinkGC::PreciseGC: |
| 467 return "PreciseGC"; | 402 return "PreciseGC"; |
| 468 case BlinkGC::ConservativeGC: | 403 case BlinkGC::ConservativeGC: |
| (...skipping 17 matching lines...) Expand all Loading... |
| 486 ThreadState* state = ThreadState::current(); | 421 ThreadState* state = ThreadState::current(); |
| 487 // Nested collectGarbage() invocations aren't supported. | 422 // Nested collectGarbage() invocations aren't supported. |
| 488 RELEASE_ASSERT(!state->isGCForbidden()); | 423 RELEASE_ASSERT(!state->isGCForbidden()); |
| 489 state->completeSweep(); | 424 state->completeSweep(); |
| 490 | 425 |
| 491 OwnPtr<Visitor> visitor = Visitor::create(state, gcType); | 426 OwnPtr<Visitor> visitor = Visitor::create(state, gcType); |
| 492 | 427 |
| 493 SafePointScope safePointScope(stackState, state); | 428 SafePointScope safePointScope(stackState, state); |
| 494 | 429 |
| 495 // Resume all parked threads upon leaving this scope. | 430 // Resume all parked threads upon leaving this scope. |
| 496 ParkThreadsScope parkThreadsScope(state); | 431 ParkThreadsScope parkThreadsScope; |
| 497 | 432 |
| 498 // Try to park the other threads. If we're unable to, bail out of the GC. | 433 // Try to park the other threads. If we're unable to, bail out of the GC. |
| 499 if (!parkThreadsScope.parkThreads()) | 434 if (!parkThreadsScope.parkThreads(state)) |
| 500 return; | 435 return; |
| 501 | 436 |
| 502 ScriptForbiddenIfMainThreadScope scriptForbidden; | 437 ScriptForbiddenIfMainThreadScope scriptForbidden; |
| 503 | 438 |
| 504 TRACE_EVENT2("blink_gc,devtools.timeline", "BlinkGCMarking", | 439 TRACE_EVENT2("blink_gc,devtools.timeline", "BlinkGCMarking", |
| 505 "lazySweeping", gcType == BlinkGC::GCWithoutSweep, | 440 "lazySweeping", gcType == BlinkGC::GCWithoutSweep, |
| 506 "gcReason", gcReasonString(reason)); | 441 "gcReason", gcReasonString(reason)); |
| 507 TRACE_EVENT_SCOPED_SAMPLING_STATE("blink_gc", "BlinkGC"); | 442 TRACE_EVENT_SCOPED_SAMPLING_STATE("blink_gc", "BlinkGC"); |
| 508 double startTime = WTF::currentTimeMS(); | 443 double startTime = WTF::currentTimeMS(); |
| 509 | 444 |
| 510 if (gcType == BlinkGC::TakeSnapshot) | 445 if (gcType == BlinkGC::TakeSnapshot) |
| 511 BlinkGCMemoryDumpProvider::instance()->clearProcessDumpForCurrentGC(); | 446 BlinkGCMemoryDumpProvider::instance()->clearProcessDumpForCurrentGC(); |
| 512 | 447 |
| 513 // Disallow allocation during garbage collection (but not during the | 448 // Disallow allocation during garbage collection (but not during the |
| 514 // finalization that happens when the visitorScope is torn down). | 449 // finalization that happens when the visitorScope is torn down). |
| 515 ThreadState::NoAllocationScope noAllocationScope(state); | 450 ThreadState::NoAllocationScope noAllocationScope(state); |
| 516 | 451 |
| 517 state->heap().preGC(); | 452 preGC(); |
| 518 | 453 |
| 519 StackFrameDepthScope stackDepthScope; | 454 StackFrameDepthScope stackDepthScope; |
| 520 | 455 |
| 521 size_t totalObjectSize = state->heap().heapStats().allocatedObjectSize() + s
tate->heap().heapStats().markedObjectSize(); | 456 size_t totalObjectSize = ThreadHeap::heapStats().allocatedObjectSize() + Thr
eadHeap::heapStats().markedObjectSize(); |
| 522 if (gcType != BlinkGC::TakeSnapshot) | 457 if (gcType != BlinkGC::TakeSnapshot) |
| 523 state->heap().resetHeapCounters(); | 458 ThreadHeap::resetHeapCounters(); |
| 524 | 459 |
| 525 // 1. Trace persistent roots. | 460 // 1. Trace persistent roots. |
| 526 state->heap().visitPersistentRoots(visitor.get()); | 461 ThreadState::visitPersistentRoots(visitor.get()); |
| 527 | 462 |
| 528 // 2. Trace objects reachable from the stack. We do this independent of the | 463 // 2. Trace objects reachable from the stack. We do this independent of the |
| 529 // given stackState since other threads might have a different stack state. | 464 // given stackState since other threads might have a different stack state. |
| 530 state->heap().visitStackRoots(visitor.get()); | 465 ThreadState::visitStackRoots(visitor.get()); |
| 531 | 466 |
| 532 // 3. Transitive closure to trace objects including ephemerons. | 467 // 3. Transitive closure to trace objects including ephemerons. |
| 533 state->heap().processMarkingStack(visitor.get()); | 468 processMarkingStack(visitor.get()); |
| 534 | 469 |
| 535 state->heap().postMarkingProcessing(visitor.get()); | 470 postMarkingProcessing(visitor.get()); |
| 536 state->heap().globalWeakProcessing(visitor.get()); | 471 globalWeakProcessing(visitor.get()); |
| 537 | 472 |
| 538 // Now we can delete all orphaned pages because there are no dangling | 473 // Now we can delete all orphaned pages because there are no dangling |
| 539 // pointers to the orphaned pages. (If we have such dangling pointers, | 474 // pointers to the orphaned pages. (If we have such dangling pointers, |
| 540 // we should have crashed during marking before getting here.) | 475 // we should have crashed during marking before getting here.) |
| 541 state->heap().getOrphanedPagePool()->decommitOrphanedPages(); | 476 getOrphanedPagePool()->decommitOrphanedPages(); |
| 542 | 477 |
| 543 double markingTimeInMilliseconds = WTF::currentTimeMS() - startTime; | 478 double markingTimeInMilliseconds = WTF::currentTimeMS() - startTime; |
| 544 state->heap().heapStats().setEstimatedMarkingTimePerByte(totalObjectSize ? (
markingTimeInMilliseconds / 1000 / totalObjectSize) : 0); | 479 ThreadHeap::heapStats().setEstimatedMarkingTimePerByte(totalObjectSize ? (ma
rkingTimeInMilliseconds / 1000 / totalObjectSize) : 0); |
| 545 | 480 |
| 546 #if PRINT_HEAP_STATS | 481 #if PRINT_HEAP_STATS |
| 547 dataLogF("ThreadHeap::collectGarbage (gcReason=%s, lazySweeping=%d, time=%.1
lfms)\n", gcReasonString(reason), gcType == BlinkGC::GCWithoutSweep, markingTime
InMilliseconds); | 482 dataLogF("ThreadHeap::collectGarbage (gcReason=%s, lazySweeping=%d, time=%.1
lfms)\n", gcReasonString(reason), gcType == BlinkGC::GCWithoutSweep, markingTime
InMilliseconds); |
| 548 #endif | 483 #endif |
| 549 | 484 |
| 550 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, markingTimeHistogram,
new CustomCountHistogram("BlinkGC.CollectGarbage", 0, 10 * 1000, 50)); | 485 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, markingTimeHistogram,
new CustomCountHistogram("BlinkGC.CollectGarbage", 0, 10 * 1000, 50)); |
| 551 markingTimeHistogram.count(markingTimeInMilliseconds); | 486 markingTimeHistogram.count(markingTimeInMilliseconds); |
| 552 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, totalObjectSpaceHistog
ram, new CustomCountHistogram("BlinkGC.TotalObjectSpace", 0, 4 * 1024 * 1024, 50
)); | 487 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, totalObjectSpaceHistog
ram, new CustomCountHistogram("BlinkGC.TotalObjectSpace", 0, 4 * 1024 * 1024, 50
)); |
| 553 totalObjectSpaceHistogram.count(ProcessHeap::totalAllocatedObjectSize() / 10
24); | 488 totalObjectSpaceHistogram.count(ProcessHeap::totalAllocatedObjectSize() / 10
24); |
| 554 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, totalAllocatedSpaceHis
togram, new CustomCountHistogram("BlinkGC.TotalAllocatedSpace", 0, 4 * 1024 * 10
24, 50)); | 489 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, totalAllocatedSpaceHis
togram, new CustomCountHistogram("BlinkGC.TotalAllocatedSpace", 0, 4 * 1024 * 10
24, 50)); |
| 555 totalAllocatedSpaceHistogram.count(ProcessHeap::totalAllocatedSpace() / 1024
); | 490 totalAllocatedSpaceHistogram.count(ProcessHeap::totalAllocatedSpace() / 1024
); |
| 556 DEFINE_THREAD_SAFE_STATIC_LOCAL(EnumerationHistogram, gcReasonHistogram, new
EnumerationHistogram("BlinkGC.GCReason", BlinkGC::NumberOfGCReason)); | 491 DEFINE_THREAD_SAFE_STATIC_LOCAL(EnumerationHistogram, gcReasonHistogram, new
EnumerationHistogram("BlinkGC.GCReason", BlinkGC::NumberOfGCReason)); |
| 557 gcReasonHistogram.count(reason); | 492 gcReasonHistogram.count(reason); |
| 558 | 493 |
| 559 state->heap().m_lastGCReason = reason; | 494 s_lastGCReason = reason; |
| 560 | 495 |
| 561 ThreadHeap::reportMemoryUsageHistogram(); | 496 ThreadHeap::reportMemoryUsageHistogram(); |
| 562 WTF::Partitions::reportMemoryUsageHistogram(); | 497 WTF::Partitions::reportMemoryUsageHistogram(); |
| 563 | 498 |
| 564 state->heap().postGC(gcType); | 499 postGC(gcType); |
| 565 state->heap().decommitCallbackStacks(); | 500 ThreadHeap::decommitCallbackStacks(); |
| 566 } | 501 } |
| 567 | 502 |
| 568 void ThreadHeap::collectGarbageForTerminatingThread(ThreadState* state) | 503 void ThreadHeap::collectGarbageForTerminatingThread(ThreadState* state) |
| 569 { | 504 { |
| 570 { | 505 { |
| 571 // A thread-specific termination GC must not allow other global GCs to g
o | 506 // A thread-specific termination GC must not allow other global GCs to g
o |
| 572 // ahead while it is running, hence the termination GC does not enter a | 507 // ahead while it is running, hence the termination GC does not enter a |
| 573 // safepoint. VisitorScope will not enter also a safepoint scope for | 508 // safepoint. VisitorScope will not enter also a safepoint scope for |
| 574 // ThreadTerminationGC. | 509 // ThreadTerminationGC. |
| 575 OwnPtr<Visitor> visitor = Visitor::create(state, BlinkGC::ThreadTerminat
ionGC); | 510 OwnPtr<Visitor> visitor = Visitor::create(state, BlinkGC::ThreadTerminat
ionGC); |
| 576 | 511 |
| 577 ThreadState::NoAllocationScope noAllocationScope(state); | 512 ThreadState::NoAllocationScope noAllocationScope(state); |
| 578 | 513 |
| 579 state->preGC(); | 514 state->preGC(); |
| 580 | 515 |
| 581 // 1. Trace the thread local persistent roots. For thread local GCs we | 516 // 1. Trace the thread local persistent roots. For thread local GCs we |
| 582 // don't trace the stack (ie. no conservative scanning) since this is | 517 // don't trace the stack (ie. no conservative scanning) since this is |
| 583 // only called during thread shutdown where there should be no objects | 518 // only called during thread shutdown where there should be no objects |
| 584 // on the stack. | 519 // on the stack. |
| 585 // We also assume that orphaned pages have no objects reachable from | 520 // We also assume that orphaned pages have no objects reachable from |
| 586 // persistent handles on other threads or CrossThreadPersistents. The | 521 // persistent handles on other threads or CrossThreadPersistents. The |
| 587 // only cases where this could happen is if a subsequent conservative | 522 // only cases where this could happen is if a subsequent conservative |
| 588 // global GC finds a "pointer" on the stack or due to a programming | 523 // global GC finds a "pointer" on the stack or due to a programming |
| 589 // error where an object has a dangling cross-thread pointer to an | 524 // error where an object has a dangling cross-thread pointer to an |
| 590 // object on this heap. | 525 // object on this heap. |
| 591 state->visitPersistents(visitor.get()); | 526 state->visitPersistents(visitor.get()); |
| 592 | 527 |
| 593 // 2. Trace objects reachable from the thread's persistent roots | 528 // 2. Trace objects reachable from the thread's persistent roots |
| 594 // including ephemerons. | 529 // including ephemerons. |
| 595 state->heap().processMarkingStack(visitor.get()); | 530 processMarkingStack(visitor.get()); |
| 596 | 531 |
| 597 state->heap().postMarkingProcessing(visitor.get()); | 532 postMarkingProcessing(visitor.get()); |
| 598 state->heap().globalWeakProcessing(visitor.get()); | 533 globalWeakProcessing(visitor.get()); |
| 599 | 534 |
| 600 state->postGC(BlinkGC::GCWithSweep); | 535 state->postGC(BlinkGC::GCWithSweep); |
| 601 state->heap().decommitCallbackStacks(); | 536 ThreadHeap::decommitCallbackStacks(); |
| 602 } | 537 } |
| 603 state->preSweep(); | 538 state->preSweep(); |
| 604 } | 539 } |
| 605 | 540 |
| 606 void ThreadHeap::processMarkingStack(Visitor* visitor) | 541 void ThreadHeap::processMarkingStack(Visitor* visitor) |
| 607 { | 542 { |
| 608 // Ephemeron fixed point loop. | 543 // Ephemeron fixed point loop. |
| 609 do { | 544 do { |
| 610 { | 545 { |
| 611 // Iteratively mark all objects that are reachable from the objects | 546 // Iteratively mark all objects that are reachable from the objects |
| 612 // currently pushed onto the marking stack. | 547 // currently pushed onto the marking stack. |
| 613 TRACE_EVENT0("blink_gc", "ThreadHeap::processMarkingStackSingleThrea
ded"); | 548 TRACE_EVENT0("blink_gc", "ThreadHeap::processMarkingStackSingleThrea
ded"); |
| 614 while (popAndInvokeTraceCallback(visitor)) { } | 549 while (popAndInvokeTraceCallback(visitor)) { } |
| 615 } | 550 } |
| 616 | 551 |
| 617 { | 552 { |
| 618 // Mark any strong pointers that have now become reachable in | 553 // Mark any strong pointers that have now become reachable in |
| 619 // ephemeron maps. | 554 // ephemeron maps. |
| 620 TRACE_EVENT0("blink_gc", "ThreadHeap::processEphemeronStack"); | 555 TRACE_EVENT0("blink_gc", "ThreadHeap::processEphemeronStack"); |
| 621 m_ephemeronStack->invokeEphemeronCallbacks(visitor); | 556 s_ephemeronStack->invokeEphemeronCallbacks(visitor); |
| 622 } | 557 } |
| 623 | 558 |
| 624 // Rerun loop if ephemeron processing queued more objects for tracing. | 559 // Rerun loop if ephemeron processing queued more objects for tracing. |
| 625 } while (!m_markingStack->isEmpty()); | 560 } while (!s_markingStack->isEmpty()); |
| 626 } | 561 } |
| 627 | 562 |
| 628 void ThreadHeap::postMarkingProcessing(Visitor* visitor) | 563 void ThreadHeap::postMarkingProcessing(Visitor* visitor) |
| 629 { | 564 { |
| 630 TRACE_EVENT0("blink_gc", "ThreadHeap::postMarkingProcessing"); | 565 TRACE_EVENT0("blink_gc", "ThreadHeap::postMarkingProcessing"); |
| 631 // Call post-marking callbacks including: | 566 // Call post-marking callbacks including: |
| 632 // 1. the ephemeronIterationDone callbacks on weak tables to do cleanup | 567 // 1. the ephemeronIterationDone callbacks on weak tables to do cleanup |
| 633 // (specifically to clear the queued bits for weak hash tables), and | 568 // (specifically to clear the queued bits for weak hash tables), and |
| 634 // 2. the markNoTracing callbacks on collection backings to mark them | 569 // 2. the markNoTracing callbacks on collection backings to mark them |
| 635 // if they are only reachable from their front objects. | 570 // if they are only reachable from their front objects. |
| 636 while (popAndInvokePostMarkingCallback(visitor)) { } | 571 while (popAndInvokePostMarkingCallback(visitor)) { } |
| 637 | 572 |
| 638 // Post-marking callbacks should not trace any objects and | 573 // Post-marking callbacks should not trace any objects and |
| 639 // therefore the marking stack should be empty after the | 574 // therefore the marking stack should be empty after the |
| 640 // post-marking callbacks. | 575 // post-marking callbacks. |
| 641 ASSERT(m_markingStack->isEmpty()); | 576 ASSERT(s_markingStack->isEmpty()); |
| 642 } | 577 } |
| 643 | 578 |
| 644 void ThreadHeap::globalWeakProcessing(Visitor* visitor) | 579 void ThreadHeap::globalWeakProcessing(Visitor* visitor) |
| 645 { | 580 { |
| 646 TRACE_EVENT0("blink_gc", "ThreadHeap::globalWeakProcessing"); | 581 TRACE_EVENT0("blink_gc", "ThreadHeap::globalWeakProcessing"); |
| 647 double startTime = WTF::currentTimeMS(); | 582 double startTime = WTF::currentTimeMS(); |
| 648 | 583 |
| 649 // Call weak callbacks on objects that may now be pointing to dead objects. | 584 // Call weak callbacks on objects that may now be pointing to dead objects. |
| 650 while (popAndInvokeGlobalWeakCallback(visitor)) { } | 585 while (popAndInvokeGlobalWeakCallback(visitor)) { } |
| 651 | 586 |
| 652 // It is not permitted to trace pointers of live objects in the weak | 587 // It is not permitted to trace pointers of live objects in the weak |
| 653 // callback phase, so the marking stack should still be empty here. | 588 // callback phase, so the marking stack should still be empty here. |
| 654 ASSERT(m_markingStack->isEmpty()); | 589 ASSERT(s_markingStack->isEmpty()); |
| 655 | 590 |
| 656 double timeForGlobalWeakProcessing = WTF::currentTimeMS() - startTime; | 591 double timeForGlobalWeakProcessing = WTF::currentTimeMS() - startTime; |
| 657 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, globalWeakTimeHistogra
m, new CustomCountHistogram("BlinkGC.TimeForGlobalWeakProcessing", 1, 10 * 1000,
50)); | 592 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, globalWeakTimeHistogra
m, new CustomCountHistogram("BlinkGC.TimeForGlobalWeakProcessing", 1, 10 * 1000,
50)); |
| 658 globalWeakTimeHistogram.count(timeForGlobalWeakProcessing); | 593 globalWeakTimeHistogram.count(timeForGlobalWeakProcessing); |
| 659 } | 594 } |
| 660 | 595 |
| 661 void ThreadHeap::collectAllGarbage() | 596 void ThreadHeap::collectAllGarbage() |
| 662 { | 597 { |
| 663 // We need to run multiple GCs to collect a chain of persistent handles. | 598 // We need to run multiple GCs to collect a chain of persistent handles. |
| 664 size_t previousLiveObjects = 0; | 599 size_t previousLiveObjects = 0; |
| 665 ThreadState* state = ThreadState::current(); | |
| 666 for (int i = 0; i < 5; ++i) { | 600 for (int i = 0; i < 5; ++i) { |
| 667 collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Bli
nkGC::ForcedGC); | 601 collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, Bli
nkGC::ForcedGC); |
| 668 size_t liveObjects = state->heap().heapStats().markedObjectSize(); | 602 size_t liveObjects = ThreadHeap::heapStats().markedObjectSize(); |
| 669 if (liveObjects == previousLiveObjects) | 603 if (liveObjects == previousLiveObjects) |
| 670 break; | 604 break; |
| 671 previousLiveObjects = liveObjects; | 605 previousLiveObjects = liveObjects; |
| 672 } | 606 } |
| 673 } | 607 } |
| 674 | 608 |
| 675 void ThreadHeap::reportMemoryUsageHistogram() | 609 void ThreadHeap::reportMemoryUsageHistogram() |
| 676 { | 610 { |
| 677 static size_t supportedMaxSizeInMB = 4 * 1024; | 611 static size_t supportedMaxSizeInMB = 4 * 1024; |
| 678 static size_t observedMaxSizeInMB = 0; | 612 static size_t observedMaxSizeInMB = 0; |
| 679 | 613 |
| 680 // We only report the memory in the main thread. | 614 // We only report the memory in the main thread. |
| 681 if (!isMainThread()) | 615 if (!isMainThread()) |
| 682 return; | 616 return; |
| 683 // +1 is for rounding up the sizeInMB. | 617 // +1 is for rounding up the sizeInMB. |
| 684 size_t sizeInMB = ThreadState::current()->heap().heapStats().allocatedSpace(
) / 1024 / 1024 + 1; | 618 size_t sizeInMB = ThreadHeap::heapStats().allocatedSpace() / 1024 / 1024 + 1
; |
| 685 if (sizeInMB >= supportedMaxSizeInMB) | 619 if (sizeInMB >= supportedMaxSizeInMB) |
| 686 sizeInMB = supportedMaxSizeInMB - 1; | 620 sizeInMB = supportedMaxSizeInMB - 1; |
| 687 if (sizeInMB > observedMaxSizeInMB) { | 621 if (sizeInMB > observedMaxSizeInMB) { |
| 688 // Send a UseCounter only when we see the highest memory usage | 622 // Send a UseCounter only when we see the highest memory usage |
| 689 // we've ever seen. | 623 // we've ever seen. |
| 690 DEFINE_THREAD_SAFE_STATIC_LOCAL(EnumerationHistogram, commitedSizeHistog
ram, new EnumerationHistogram("BlinkGC.CommittedSize", supportedMaxSizeInMB)); | 624 DEFINE_THREAD_SAFE_STATIC_LOCAL(EnumerationHistogram, commitedSizeHistog
ram, new EnumerationHistogram("BlinkGC.CommittedSize", supportedMaxSizeInMB)); |
| 691 commitedSizeHistogram.count(sizeInMB); | 625 commitedSizeHistogram.count(sizeInMB); |
| 692 observedMaxSizeInMB = sizeInMB; | 626 observedMaxSizeInMB = sizeInMB; |
| 693 } | 627 } |
| 694 } | 628 } |
| 695 | 629 |
| 696 void ThreadHeap::reportMemoryUsageForTracing() | 630 void ThreadHeap::reportMemoryUsageForTracing() |
| 697 { | 631 { |
| 698 #if PRINT_HEAP_STATS | 632 #if PRINT_HEAP_STATS |
| 699 // dataLogF("allocatedSpace=%ldMB, allocatedObjectSize=%ldMB, markedObjectSi
ze=%ldMB, partitionAllocSize=%ldMB, wrapperCount=%ld, collectedWrapperCount=%ld\
n", ThreadHeap::allocatedSpace() / 1024 / 1024, ThreadHeap::allocatedObjectSize(
) / 1024 / 1024, ThreadHeap::markedObjectSize() / 1024 / 1024, WTF::Partitions::
totalSizeOfCommittedPages() / 1024 / 1024, ThreadHeap::wrapperCount(), ThreadHea
p::collectedWrapperCount()); | 633 // dataLogF("allocatedSpace=%ldMB, allocatedObjectSize=%ldMB, markedObjectSi
ze=%ldMB, partitionAllocSize=%ldMB, wrapperCount=%ld, collectedWrapperCount=%ld\
n", ThreadHeap::allocatedSpace() / 1024 / 1024, ThreadHeap::allocatedObjectSize(
) / 1024 / 1024, ThreadHeap::markedObjectSize() / 1024 / 1024, WTF::Partitions::
totalSizeOfCommittedPages() / 1024 / 1024, ThreadHeap::wrapperCount(), ThreadHea
p::collectedWrapperCount()); |
| 700 #endif | 634 #endif |
| 701 | 635 |
| 702 bool gcTracingEnabled; | 636 bool gcTracingEnabled; |
| 703 TRACE_EVENT_CATEGORY_GROUP_ENABLED("blink_gc", &gcTracingEnabled); | 637 TRACE_EVENT_CATEGORY_GROUP_ENABLED("blink_gc", &gcTracingEnabled); |
| 704 if (!gcTracingEnabled) | 638 if (!gcTracingEnabled) |
| 705 return; | 639 return; |
| 706 | 640 |
| 707 ThreadHeap& heap = ThreadState::current()->heap(); | |
| 708 // These values are divided by 1024 to avoid overflow in practical cases (TR
ACE_COUNTER values are 32-bit ints). | 641 // These values are divided by 1024 to avoid overflow in practical cases (TR
ACE_COUNTER values are 32-bit ints). |
| 709 // They are capped to INT_MAX just in case. | 642 // They are capped to INT_MAX just in case. |
| 710 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadHeap::allocated
ObjectSizeKB", std::min(heap.heapStats().allocatedObjectSize() / 1024, static_ca
st<size_t>(INT_MAX))); | 643 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadHeap::allocated
ObjectSizeKB", std::min(ThreadHeap::heapStats().allocatedObjectSize() / 1024, st
atic_cast<size_t>(INT_MAX))); |
| 711 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadHeap::markedObj
ectSizeKB", std::min(heap.heapStats().markedObjectSize() / 1024, static_cast<siz
e_t>(INT_MAX))); | 644 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadHeap::markedObj
ectSizeKB", std::min(ThreadHeap::heapStats().markedObjectSize() / 1024, static_c
ast<size_t>(INT_MAX))); |
| 712 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadHeap::markedObj
ectSizeAtLastCompleteSweepKB", std::min(heap.heapStats().markedObjectSizeAtLastC
ompleteSweep() / 1024, static_cast<size_t>(INT_MAX))); | 645 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadHeap::markedObj
ectSizeAtLastCompleteSweepKB", std::min(ThreadHeap::heapStats().markedObjectSize
AtLastCompleteSweep() / 1024, static_cast<size_t>(INT_MAX))); |
| 713 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadHeap::allocated
SpaceKB", std::min(heap.heapStats().allocatedSpace() / 1024, static_cast<size_t>
(INT_MAX))); | 646 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadHeap::allocated
SpaceKB", std::min(ThreadHeap::heapStats().allocatedSpace() / 1024, static_cast<
size_t>(INT_MAX))); |
| 714 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadHeap::objectSiz
eAtLastGCKB", std::min(heap.heapStats().objectSizeAtLastGC() / 1024, static_cast
<size_t>(INT_MAX))); | 647 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadHeap::objectSiz
eAtLastGCKB", std::min(ThreadHeap::heapStats().objectSizeAtLastGC() / 1024, stat
ic_cast<size_t>(INT_MAX))); |
| 715 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadHeap::wrapperCo
unt", std::min(heap.heapStats().wrapperCount(), static_cast<size_t>(INT_MAX))); | 648 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadHeap::wrapperCo
unt", std::min(ThreadHeap::heapStats().wrapperCount(), static_cast<size_t>(INT_M
AX))); |
| 716 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadHeap::wrapperCo
untAtLastGC", std::min(heap.heapStats().wrapperCountAtLastGC(), static_cast<size
_t>(INT_MAX))); | 649 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadHeap::heapStats
().wrapperCountAtLastGC", std::min(ThreadHeap::heapStats().wrapperCountAtLastGC(
), static_cast<size_t>(INT_MAX))); |
| 717 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadHeap::collected
WrapperCount", std::min(heap.heapStats().collectedWrapperCount(), static_cast<si
ze_t>(INT_MAX))); | 650 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadHeap::collected
WrapperCount", std::min(ThreadHeap::heapStats().collectedWrapperCount(), static_
cast<size_t>(INT_MAX))); |
| 718 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadHeap::partition
AllocSizeAtLastGCKB", std::min(heap.heapStats().partitionAllocSizeAtLastGC() / 1
024, static_cast<size_t>(INT_MAX))); | 651 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadHeap::partition
AllocSizeAtLastGCKB", std::min(ThreadHeap::heapStats().partitionAllocSizeAtLastG
C() / 1024, static_cast<size_t>(INT_MAX))); |
| 719 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "Partitions::totalSize
OfCommittedPagesKB", std::min(WTF::Partitions::totalSizeOfCommittedPages() / 102
4, static_cast<size_t>(INT_MAX))); | 652 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "Partitions::totalSize
OfCommittedPagesKB", std::min(WTF::Partitions::totalSizeOfCommittedPages() / 102
4, static_cast<size_t>(INT_MAX))); |
| 720 } | 653 } |
| 721 | 654 |
| 722 size_t ThreadHeap::objectPayloadSizeForTesting() | 655 size_t ThreadHeap::objectPayloadSizeForTesting() |
| 723 { | 656 { |
| 724 // MEMO: is threadAttachMutex locked? | |
| 725 size_t objectPayloadSize = 0; | 657 size_t objectPayloadSize = 0; |
| 726 for (ThreadState* state : m_threads) { | 658 for (ThreadState* state : ThreadState::attachedThreads()) { |
| 727 state->setGCState(ThreadState::GCRunning); | 659 state->setGCState(ThreadState::GCRunning); |
| 728 state->makeConsistentForGC(); | 660 state->makeConsistentForGC(); |
| 729 objectPayloadSize += state->objectPayloadSizeForTesting(); | 661 objectPayloadSize += state->objectPayloadSizeForTesting(); |
| 730 state->setGCState(ThreadState::EagerSweepScheduled); | 662 state->setGCState(ThreadState::EagerSweepScheduled); |
| 731 state->setGCState(ThreadState::Sweeping); | 663 state->setGCState(ThreadState::Sweeping); |
| 732 state->setGCState(ThreadState::NoGCScheduled); | 664 state->setGCState(ThreadState::NoGCScheduled); |
| 733 } | 665 } |
| 734 return objectPayloadSize; | 666 return objectPayloadSize; |
| 735 } | 667 } |
| 736 | 668 |
| 737 void ThreadHeap::visitPersistentRoots(Visitor* visitor) | 669 RegionTree* ThreadHeap::getRegionTree() |
| 670 { |
| 671 DEFINE_THREAD_SAFE_STATIC_LOCAL(RegionTree, tree, new RegionTree); |
| 672 return &tree; |
| 673 } |
| 674 |
| 675 BasePage* ThreadHeap::lookup(Address address) |
| 738 { | 676 { |
| 739 ASSERT(ThreadState::current()->isInGC()); | 677 ASSERT(ThreadState::current()->isInGC()); |
| 740 TRACE_EVENT0("blink_gc", "ThreadHeap::visitPersistentRoots"); | 678 if (PageMemoryRegion* region = ThreadHeap::getRegionTree()->lookup(address))
{ |
| 741 ProcessHeap::crossThreadPersistentRegion().tracePersistentNodes(visitor); | |
| 742 | |
| 743 for (ThreadState* state : m_threads) { | |
| 744 state->visitPersistents(visitor); | |
| 745 } | |
| 746 } | |
| 747 | |
| 748 void ThreadHeap::visitStackRoots(Visitor* visitor) | |
| 749 { | |
| 750 ASSERT(ThreadState::current()->isInGC()); | |
| 751 TRACE_EVENT0("blink_gc", "ThreadHeap::visitStackRoots"); | |
| 752 for (ThreadState* state : m_threads) { | |
| 753 state->visitStack(visitor); | |
| 754 } | |
| 755 } | |
| 756 | |
| 757 void ThreadHeap::checkAndPark(ThreadState* threadState, SafePointAwareMutexLocke
r* locker) | |
| 758 { | |
| 759 m_safePointBarrier->checkAndPark(threadState, locker); | |
| 760 } | |
| 761 | |
| 762 void ThreadHeap::enterSafePoint(ThreadState* threadState) | |
| 763 { | |
| 764 m_safePointBarrier->enterSafePoint(threadState); | |
| 765 } | |
| 766 | |
| 767 void ThreadHeap::leaveSafePoint(ThreadState* threadState, SafePointAwareMutexLoc
ker* locker) | |
| 768 { | |
| 769 m_safePointBarrier->leaveSafePoint(threadState, locker); | |
| 770 } | |
| 771 | |
| 772 BasePage* ThreadHeap::lookupPageForAddress(Address address) | |
| 773 { | |
| 774 ASSERT(ThreadState::current()->isInGC()); | |
| 775 if (PageMemoryRegion* region = m_regionTree->lookup(address)) { | |
| 776 BasePage* page = region->pageFromAddress(address); | 679 BasePage* page = region->pageFromAddress(address); |
| 777 return page && !page->orphaned() ? page : nullptr; | 680 return page && !page->orphaned() ? page : nullptr; |
| 778 } | 681 } |
| 779 return nullptr; | 682 return nullptr; |
| 780 } | 683 } |
| 781 | 684 |
| 782 void ThreadHeap::resetHeapCounters() | 685 void ThreadHeap::resetHeapCounters() |
| 783 { | 686 { |
| 784 ASSERT(ThreadState::current()->isInGC()); | 687 ASSERT(ThreadState::current()->isInGC()); |
| 785 | 688 |
| 786 ThreadHeap::reportMemoryUsageForTracing(); | 689 ThreadHeap::reportMemoryUsageForTracing(); |
| 787 | 690 |
| 788 ProcessHeap::decreaseTotalAllocatedObjectSize(m_stats.allocatedObjectSize())
; | 691 ProcessHeap::resetHeapCounters(); |
| 789 ProcessHeap::decreaseTotalMarkedObjectSize(m_stats.markedObjectSize()); | 692 ThreadHeap::heapStats().reset(); |
| 790 | 693 for (ThreadState* state : ThreadState::attachedThreads()) |
| 791 m_stats.reset(); | |
| 792 for (ThreadState* state : m_threads) | |
| 793 state->resetHeapCounters(); | 694 state->resetHeapCounters(); |
| 794 } | 695 } |
| 795 | 696 |
| 796 ThreadHeap* ThreadHeap::s_mainThreadHeap = nullptr; | 697 ThreadHeapStats& ThreadHeap::heapStats() |
| 698 { |
| 699 DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadHeapStats, stats, new ThreadHeapStats(
)); |
| 700 return stats; |
| 701 } |
| 702 |
| 703 CallbackStack* ThreadHeap::s_markingStack; |
| 704 CallbackStack* ThreadHeap::s_postMarkingCallbackStack; |
| 705 CallbackStack* ThreadHeap::s_globalWeakCallbackStack; |
| 706 CallbackStack* ThreadHeap::s_ephemeronStack; |
| 707 HeapDoesNotContainCache* ThreadHeap::s_heapDoesNotContainCache; |
| 708 FreePagePool* ThreadHeap::s_freePagePool; |
| 709 OrphanedPagePool* ThreadHeap::s_orphanedPagePool; |
| 710 |
| 711 BlinkGC::GCReason ThreadHeap::s_lastGCReason = BlinkGC::NumberOfGCReason; |
| 797 | 712 |
| 798 } // namespace blink | 713 } // namespace blink |
| OLD | NEW |