| 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 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 69 #include <pthread_np.h> | 69 #include <pthread_np.h> |
| 70 #endif | 70 #endif |
| 71 | 71 |
| 72 namespace blink { | 72 namespace blink { |
| 73 | 73 |
| 74 WTF::ThreadSpecific<ThreadState*>* ThreadState::s_threadSpecific = nullptr; | 74 WTF::ThreadSpecific<ThreadState*>* ThreadState::s_threadSpecific = nullptr; |
| 75 uintptr_t ThreadState::s_mainThreadStackStart = 0; | 75 uintptr_t ThreadState::s_mainThreadStackStart = 0; |
| 76 uintptr_t ThreadState::s_mainThreadUnderestimatedStackSize = 0; | 76 uintptr_t ThreadState::s_mainThreadUnderestimatedStackSize = 0; |
| 77 uint8_t ThreadState::s_mainThreadStateStorage[sizeof(ThreadState)]; | 77 uint8_t ThreadState::s_mainThreadStateStorage[sizeof(ThreadState)]; |
| 78 SafePointBarrier* ThreadState::s_safePointBarrier = nullptr; | 78 SafePointBarrier* ThreadState::s_safePointBarrier = nullptr; |
| 79 #if ENABLE(ASSERT) |
| 80 int ThreadState::s_selfKeepAliveAllocationsOnMainThread = 0; |
| 81 #endif |
| 79 | 82 |
| 80 RecursiveMutex& ThreadState::threadAttachMutex() | 83 RecursiveMutex& ThreadState::threadAttachMutex() |
| 81 { | 84 { |
| 82 AtomicallyInitializedStaticReference(RecursiveMutex, mutex, (new RecursiveMu
tex)); | 85 AtomicallyInitializedStaticReference(RecursiveMutex, mutex, (new RecursiveMu
tex)); |
| 83 return mutex; | 86 return mutex; |
| 84 } | 87 } |
| 85 | 88 |
| 86 ThreadState::ThreadState() | 89 ThreadState::ThreadState() |
| 87 : m_thread(currentThread()) | 90 : m_thread(currentThread()) |
| 88 , m_persistentRegion(adoptPtr(new PersistentRegion())) | 91 , m_persistentRegion(adoptPtr(new PersistentRegion())) |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 159 | 162 |
| 160 // Thread-local storage shouldn't be disposed, so we don't call ~ThreadSpeci
fic(). | 163 // Thread-local storage shouldn't be disposed, so we don't call ~ThreadSpeci
fic(). |
| 161 } | 164 } |
| 162 | 165 |
| 163 void ThreadState::attachMainThread() | 166 void ThreadState::attachMainThread() |
| 164 { | 167 { |
| 165 RELEASE_ASSERT(!Heap::s_shutdownCalled); | 168 RELEASE_ASSERT(!Heap::s_shutdownCalled); |
| 166 MutexLocker locker(threadAttachMutex()); | 169 MutexLocker locker(threadAttachMutex()); |
| 167 ThreadState* state = new(s_mainThreadStateStorage) ThreadState(); | 170 ThreadState* state = new(s_mainThreadStateStorage) ThreadState(); |
| 168 attachedThreads().add(state); | 171 attachedThreads().add(state); |
| 172 #if ENABLE(ASSERT) |
| 173 s_selfKeepAliveAllocationsOnMainThread = 0; |
| 174 #endif |
| 169 } | 175 } |
| 170 | 176 |
| 171 void ThreadState::detachMainThread() | 177 void ThreadState::detachMainThread() |
| 172 { | 178 { |
| 173 // Enter a safe point before trying to acquire threadAttachMutex | 179 // Enter a safe point before trying to acquire threadAttachMutex |
| 174 // to avoid dead lock if another thread is preparing for GC, has acquired | 180 // to avoid dead lock if another thread is preparing for GC, has acquired |
| 175 // threadAttachMutex and waiting for other threads to pause or reach a | 181 // threadAttachMutex and waiting for other threads to pause or reach a |
| 176 // safepoint. | 182 // safepoint. |
| 177 ThreadState* state = mainThreadState(); | 183 ThreadState* state = mainThreadState(); |
| 178 | 184 |
| 179 // 1. Finish sweeping. | 185 // 1. Finish sweeping. |
| 180 state->completeSweep(); | 186 state->completeSweep(); |
| 181 { | 187 { |
| 182 SafePointAwareMutexLocker locker(threadAttachMutex(), NoHeapPointersOnSt
ack); | 188 SafePointAwareMutexLocker locker(threadAttachMutex(), NoHeapPointersOnSt
ack); |
| 183 | 189 |
| 184 // 2. Add the main thread's heap pages to the orphaned pool. | 190 // 2. Add the main thread's heap pages to the orphaned pool. |
| 185 state->cleanupPages(); | 191 state->cleanupPages(); |
| 186 | 192 |
| 187 // 3. Detach the main thread. | 193 // 3. Detach the main thread. |
| 188 ASSERT(attachedThreads().contains(state)); | 194 ASSERT(attachedThreads().contains(state)); |
| 189 attachedThreads().remove(state); | 195 attachedThreads().remove(state); |
| 190 state->~ThreadState(); | 196 state->~ThreadState(); |
| 191 } | 197 } |
| 198 // Catch out any self-referential leaks created by the main thread. |
| 199 ASSERT(s_selfKeepAliveAllocationsOnMainThread == 0); |
| 192 shutdownHeapIfNecessary(); | 200 shutdownHeapIfNecessary(); |
| 193 } | 201 } |
| 194 | 202 |
| 195 void ThreadState::shutdownHeapIfNecessary() | 203 void ThreadState::shutdownHeapIfNecessary() |
| 196 { | 204 { |
| 197 // We don't need to enter a safe point before acquiring threadAttachMutex | 205 // We don't need to enter a safe point before acquiring threadAttachMutex |
| 198 // because this thread is already detached. | 206 // because this thread is already detached. |
| 199 | 207 |
| 200 MutexLocker locker(threadAttachMutex()); | 208 MutexLocker locker(threadAttachMutex()); |
| 201 // We start shutting down the heap if there is no running thread | 209 // We start shutting down the heap if there is no running thread |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 250 int oldCount = -1; | 258 int oldCount = -1; |
| 251 int currentCount = persistentRegion()->numberOfPersistents(); | 259 int currentCount = persistentRegion()->numberOfPersistents(); |
| 252 ASSERT(currentCount >= 0); | 260 ASSERT(currentCount >= 0); |
| 253 while (currentCount != oldCount) { | 261 while (currentCount != oldCount) { |
| 254 Heap::collectGarbageForTerminatingThread(this); | 262 Heap::collectGarbageForTerminatingThread(this); |
| 255 oldCount = currentCount; | 263 oldCount = currentCount; |
| 256 currentCount = persistentRegion()->numberOfPersistents(); | 264 currentCount = persistentRegion()->numberOfPersistents(); |
| 257 } | 265 } |
| 258 // We should not have any persistents left when getting to this point, | 266 // We should not have any persistents left when getting to this point, |
| 259 // if we have it is probably a bug so adding a debug ASSERT to catch thi
s. | 267 // if we have it is probably a bug so adding a debug ASSERT to catch thi
s. |
| 260 ASSERT(!currentCount); | 268 // (debug tip: use persistentRegion()->dumpLivePersistents() to get a li
st of |
| 269 // the remaining live Persistent<>s. In gdb, performing "info symbol" on
the |
| 270 // trace callback addresses printed should tell you what Persistent<T>s
are leaking.) |
| 271 ASSERT(!currentCount && "Persistent<>s leak on thread heap shutdown"); |
| 261 // All of pre-finalizers should be consumed. | 272 // All of pre-finalizers should be consumed. |
| 262 ASSERT(m_orderedPreFinalizers.isEmpty()); | 273 ASSERT(m_orderedPreFinalizers.isEmpty()); |
| 263 RELEASE_ASSERT(gcState() == NoGCScheduled); | 274 RELEASE_ASSERT(gcState() == NoGCScheduled); |
| 264 | 275 |
| 265 // Add pages to the orphaned page pool to ensure any global GCs from thi
s point | 276 // Add pages to the orphaned page pool to ensure any global GCs from thi
s point |
| 266 // on will not trace objects on this thread's heaps. | 277 // on will not trace objects on this thread's heaps. |
| 267 cleanupPages(); | 278 cleanupPages(); |
| 268 | 279 |
| 269 ASSERT(attachedThreads().contains(this)); | 280 ASSERT(attachedThreads().contains(this)); |
| 270 attachedThreads().remove(this); | 281 attachedThreads().remove(this); |
| (...skipping 1264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1535 for (ClassAgeCountsMap::const_iterator it = classAgeCounts.begin(), end = cl
assAgeCounts.end(); it != end; ++it) { | 1546 for (ClassAgeCountsMap::const_iterator it = classAgeCounts.begin(), end = cl
assAgeCounts.end(); it != end; ++it) { |
| 1536 json->beginArray(it->key.ascii().data()); | 1547 json->beginArray(it->key.ascii().data()); |
| 1537 for (size_t age = 0; age <= maxHeapObjectAge; ++age) | 1548 for (size_t age = 0; age <= maxHeapObjectAge; ++age) |
| 1538 json->pushInteger(it->value.ages[age]); | 1549 json->pushInteger(it->value.ages[age]); |
| 1539 json->endArray(); | 1550 json->endArray(); |
| 1540 } | 1551 } |
| 1541 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("blink_gc"), s
tatsName, this, json.release()); | 1552 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("blink_gc"), s
tatsName, this, json.release()); |
| 1542 } | 1553 } |
| 1543 #endif | 1554 #endif |
| 1544 | 1555 |
| 1556 #if ENABLE(ASSERT) |
| 1557 void ThreadState::incrementSelfKeepAliveAllocations() |
| 1558 { |
| 1559 if (!ThreadState::current()->isMainThread()) |
| 1560 return; |
| 1561 |
| 1562 s_selfKeepAliveAllocationsOnMainThread++; |
| 1563 } |
| 1564 |
| 1565 void ThreadState::decrementSelfKeepAliveAllocations() |
| 1566 { |
| 1567 if (!ThreadState::current()->isMainThread()) |
| 1568 return; |
| 1569 |
| 1570 ASSERT(s_selfKeepAliveAllocationsOnMainThread > 0); |
| 1571 s_selfKeepAliveAllocationsOnMainThread--; |
| 1572 } |
| 1573 #endif |
| 1574 |
| 1545 } // namespace blink | 1575 } // namespace blink |
| OLD | NEW |