| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions are | |
| 6 * met: | |
| 7 * | |
| 8 * * Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * * Redistributions in binary form must reproduce the above | |
| 11 * copyright notice, this list of conditions and the following disclaimer | |
| 12 * in the documentation and/or other materials provided with the | |
| 13 * distribution. | |
| 14 * * Neither the name of Google Inc. nor the names of its | |
| 15 * contributors may be used to endorse or promote products derived from | |
| 16 * this software without specific prior written permission. | |
| 17 * | |
| 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 29 */ | |
| 30 | |
| 31 #ifndef ThreadState_h | |
| 32 #define ThreadState_h | |
| 33 | |
| 34 #include "platform/PlatformExport.h" | |
| 35 #include "platform/heap/AddressSanitizer.h" | |
| 36 #include "public/platform/WebThread.h" | |
| 37 #include "wtf/HashSet.h" | |
| 38 #include "wtf/OwnPtr.h" | |
| 39 #include "wtf/PassOwnPtr.h" | |
| 40 #include "wtf/ThreadSpecific.h" | |
| 41 #include "wtf/Threading.h" | |
| 42 #include "wtf/ThreadingPrimitives.h" | |
| 43 #include "wtf/Vector.h" | |
| 44 | |
| 45 #if ENABLE(GC_PROFILE_HEAP) | |
| 46 #include "wtf/HashMap.h" | |
| 47 #endif | |
| 48 | |
| 49 namespace blink { | |
| 50 | |
| 51 class BaseHeap; | |
| 52 class BaseHeapPage; | |
| 53 class FinalizedHeapObjectHeader; | |
| 54 struct GCInfo; | |
| 55 class HeapContainsCache; | |
| 56 class HeapObjectHeader; | |
| 57 class PageMemory; | |
| 58 class PersistentNode; | |
| 59 class Visitor; | |
| 60 class SafePointBarrier; | |
| 61 class SafePointAwareMutexLocker; | |
| 62 template<typename Header> class ThreadHeap; | |
| 63 class CallbackStack; | |
| 64 | |
| 65 typedef uint8_t* Address; | |
| 66 | |
| 67 typedef void (*FinalizationCallback)(void*); | |
| 68 typedef void (*VisitorCallback)(Visitor*, void* self); | |
| 69 typedef VisitorCallback TraceCallback; | |
| 70 typedef VisitorCallback WeakPointerCallback; | |
| 71 typedef VisitorCallback EphemeronCallback; | |
| 72 | |
| 73 // ThreadAffinity indicates which threads objects can be used on. We | |
| 74 // distinguish between objects that can be used on the main thread | |
| 75 // only and objects that can be used on any thread. | |
| 76 // | |
| 77 // For objects that can only be used on the main thread we avoid going | |
| 78 // through thread-local storage to get to the thread state. | |
| 79 // | |
| 80 // FIXME: We should evaluate the performance gain. Having | |
| 81 // ThreadAffinity is complicating the implementation and we should get | |
| 82 // rid of it if it is fast enough to go through thread-local storage | |
| 83 // always. | |
| 84 enum ThreadAffinity { | |
| 85 AnyThread, | |
| 86 MainThreadOnly, | |
| 87 }; | |
| 88 | |
| 89 class Node; | |
| 90 class CSSValue; | |
| 91 | |
| 92 template<typename T, bool derivesNode = WTF::IsSubclass<typename WTF::RemoveCons
t<T>::Type, Node>::value> struct DefaultThreadingTrait; | |
| 93 | |
| 94 template<typename T> | |
| 95 struct DefaultThreadingTrait<T, false> { | |
| 96 static const ThreadAffinity Affinity = AnyThread; | |
| 97 }; | |
| 98 | |
| 99 template<typename T> | |
| 100 struct DefaultThreadingTrait<T, true> { | |
| 101 static const ThreadAffinity Affinity = MainThreadOnly; | |
| 102 }; | |
| 103 | |
| 104 template<typename T> | |
| 105 struct ThreadingTrait { | |
| 106 static const ThreadAffinity Affinity = DefaultThreadingTrait<T>::Affinity; | |
| 107 }; | |
| 108 | |
| 109 // Marks the specified class as being used from multiple threads. When | |
| 110 // a class is used from multiple threads we go through thread local | |
| 111 // storage to get the heap in which to allocate an object of that type | |
| 112 // and when allocating a Persistent handle for an object with that | |
| 113 // type. Notice that marking the base class does not automatically | |
| 114 // mark its descendants and they have to be explicitly marked. | |
| 115 #define USED_FROM_MULTIPLE_THREADS(Class) \ | |
| 116 class Class; \ | |
| 117 template<> struct ThreadingTrait<Class> { \ | |
| 118 static const ThreadAffinity Affinity = AnyThread; \ | |
| 119 } | |
| 120 | |
| 121 #define USED_FROM_MULTIPLE_THREADS_NAMESPACE(Namespace, Class) \ | |
| 122 namespace Namespace { \ | |
| 123 class Class; \ | |
| 124 } \ | |
| 125 namespace blink { \ | |
| 126 template<> struct ThreadingTrait<Namespace::Class> { \ | |
| 127 static const ThreadAffinity Affinity = AnyThread; \ | |
| 128 }; \ | |
| 129 } | |
| 130 | |
| 131 template<typename U> class ThreadingTrait<const U> : public ThreadingTrait<U> {
}; | |
| 132 | |
| 133 // List of typed heaps. The list is used to generate the implementation | |
| 134 // of typed heap related methods. | |
| 135 // | |
| 136 // To create a new typed heap add a H(<ClassName>) to the | |
| 137 // FOR_EACH_TYPED_HEAP macro below. | |
| 138 #define FOR_EACH_TYPED_HEAP(H) \ | |
| 139 H(Node) | |
| 140 | |
| 141 #define TypedHeapEnumName(Type) Type##Heap, | |
| 142 #define TypedHeapEnumNameNonFinalized(Type) Type##HeapNonFinalized, | |
| 143 | |
| 144 enum TypedHeaps { | |
| 145 GeneralHeap = 0, | |
| 146 CollectionBackingHeap, | |
| 147 FOR_EACH_TYPED_HEAP(TypedHeapEnumName) | |
| 148 GeneralHeapNonFinalized, | |
| 149 CollectionBackingHeapNonFinalized, | |
| 150 FOR_EACH_TYPED_HEAP(TypedHeapEnumNameNonFinalized) | |
| 151 // Values used for iteration of heap segments. | |
| 152 NumberOfHeaps, | |
| 153 FirstFinalizedHeap = GeneralHeap, | |
| 154 FirstNonFinalizedHeap = GeneralHeapNonFinalized, | |
| 155 NumberOfFinalizedHeaps = GeneralHeapNonFinalized, | |
| 156 NumberOfNonFinalizedHeaps = NumberOfHeaps - NumberOfFinalizedHeaps, | |
| 157 NonFinalizedHeapOffset = FirstNonFinalizedHeap | |
| 158 }; | |
| 159 | |
| 160 // Base implementation for HeapIndexTrait found below. | |
| 161 template<int heapIndex> | |
| 162 struct HeapIndexTraitBase { | |
| 163 typedef FinalizedHeapObjectHeader HeaderType; | |
| 164 typedef ThreadHeap<HeaderType> HeapType; | |
| 165 static const int finalizedIndex = heapIndex; | |
| 166 static const int nonFinalizedIndex = heapIndex + static_cast<int>(NonFinaliz
edHeapOffset); | |
| 167 static int index(bool isFinalized) | |
| 168 { | |
| 169 return isFinalized ? finalizedIndex : nonFinalizedIndex; | |
| 170 } | |
| 171 }; | |
| 172 | |
| 173 // HeapIndexTrait defines properties for each heap in the TypesHeaps enum. | |
| 174 template<int index> | |
| 175 struct HeapIndexTrait; | |
| 176 | |
| 177 template<> | |
| 178 struct HeapIndexTrait<GeneralHeap> : public HeapIndexTraitBase<GeneralHeap> { }; | |
| 179 template<> | |
| 180 struct HeapIndexTrait<GeneralHeapNonFinalized> : public HeapIndexTrait<GeneralHe
ap> { }; | |
| 181 | |
| 182 template<> | |
| 183 struct HeapIndexTrait<CollectionBackingHeap> : public HeapIndexTraitBase<Collect
ionBackingHeap> { }; | |
| 184 template<> | |
| 185 struct HeapIndexTrait<CollectionBackingHeapNonFinalized> : public HeapIndexTrait
<CollectionBackingHeap> { }; | |
| 186 | |
| 187 #define DEFINE_TYPED_HEAP_INDEX_TRAIT(Type)
\ | |
| 188 template<>
\ | |
| 189 struct HeapIndexTrait<Type##Heap> : public HeapIndexTraitBase<Type##Heap> {
\ | |
| 190 typedef HeapObjectHeader HeaderType;
\ | |
| 191 typedef ThreadHeap<HeaderType> HeapType;
\ | |
| 192 };
\ | |
| 193 template<>
\ | |
| 194 struct HeapIndexTrait<Type##HeapNonFinalized> : public HeapIndexTrait<Type##
Heap> { }; | |
| 195 FOR_EACH_TYPED_HEAP(DEFINE_TYPED_HEAP_INDEX_TRAIT) | |
| 196 #undef DEFINE_TYPED_HEAP_INDEX_TRAIT | |
| 197 | |
| 198 // HeapTypeTrait defines which heap to use for particular types. | |
| 199 // By default objects are allocated in the GeneralHeap. | |
| 200 template<typename T> | |
| 201 struct HeapTypeTrait : public HeapIndexTrait<GeneralHeap> { }; | |
| 202 | |
| 203 // We don't have any type-based mappings to the CollectionBackingHeap. | |
| 204 | |
| 205 // Each typed-heap maps the respective type to its heap. | |
| 206 #define DEFINE_TYPED_HEAP_TRAIT(Type) \ | |
| 207 class Type; \ | |
| 208 template<> \ | |
| 209 struct HeapTypeTrait<class Type> : public HeapIndexTrait<Type##Heap> { }; | |
| 210 FOR_EACH_TYPED_HEAP(DEFINE_TYPED_HEAP_TRAIT) | |
| 211 #undef DEFINE_TYPED_HEAP_TRAIT | |
| 212 | |
| 213 // A HeapStats structure keeps track of the amount of memory allocated | |
| 214 // for a Blink heap and how much of that memory is used for actual | |
| 215 // Blink objects. These stats are used in the heuristics to determine | |
| 216 // when to perform garbage collections. | |
| 217 class HeapStats { | |
| 218 public: | |
| 219 HeapStats() : m_totalObjectSpace(0), m_totalAllocatedSpace(0) { } | |
| 220 | |
| 221 size_t totalObjectSpace() const { return m_totalObjectSpace; } | |
| 222 size_t totalAllocatedSpace() const { return m_totalAllocatedSpace; } | |
| 223 | |
| 224 void add(HeapStats* other) | |
| 225 { | |
| 226 m_totalObjectSpace += other->m_totalObjectSpace; | |
| 227 m_totalAllocatedSpace += other->m_totalAllocatedSpace; | |
| 228 } | |
| 229 | |
| 230 void inline increaseObjectSpace(size_t newObjectSpace) | |
| 231 { | |
| 232 m_totalObjectSpace += newObjectSpace; | |
| 233 } | |
| 234 | |
| 235 void inline decreaseObjectSpace(size_t deadObjectSpace) | |
| 236 { | |
| 237 m_totalObjectSpace -= deadObjectSpace; | |
| 238 } | |
| 239 | |
| 240 void inline increaseAllocatedSpace(size_t newAllocatedSpace) | |
| 241 { | |
| 242 m_totalAllocatedSpace += newAllocatedSpace; | |
| 243 } | |
| 244 | |
| 245 void inline decreaseAllocatedSpace(size_t deadAllocatedSpace) | |
| 246 { | |
| 247 m_totalAllocatedSpace -= deadAllocatedSpace; | |
| 248 } | |
| 249 | |
| 250 void clear() | |
| 251 { | |
| 252 m_totalObjectSpace = 0; | |
| 253 m_totalAllocatedSpace = 0; | |
| 254 } | |
| 255 | |
| 256 bool operator==(const HeapStats& other) | |
| 257 { | |
| 258 return m_totalAllocatedSpace == other.m_totalAllocatedSpace | |
| 259 && m_totalObjectSpace == other.m_totalObjectSpace; | |
| 260 } | |
| 261 | |
| 262 private: | |
| 263 size_t m_totalObjectSpace; // Actually contains objects that may be live, no
t including headers. | |
| 264 size_t m_totalAllocatedSpace; // Allocated from the OS. | |
| 265 | |
| 266 friend class HeapTester; | |
| 267 }; | |
| 268 | |
| 269 class PLATFORM_EXPORT ThreadState { | |
| 270 WTF_MAKE_NONCOPYABLE(ThreadState); | |
| 271 public: | |
| 272 // When garbage collecting we need to know whether or not there | |
| 273 // can be pointers to Blink GC managed objects on the stack for | |
| 274 // each thread. When threads reach a safe point they record | |
| 275 // whether or not they have pointers on the stack. | |
| 276 enum StackState { | |
| 277 NoHeapPointersOnStack, | |
| 278 HeapPointersOnStack | |
| 279 }; | |
| 280 | |
| 281 class NoSweepScope { | |
| 282 public: | |
| 283 explicit NoSweepScope(ThreadState* state) : m_state(state) | |
| 284 { | |
| 285 ASSERT(!m_state->m_sweepInProgress); | |
| 286 m_state->m_sweepInProgress = true; | |
| 287 } | |
| 288 ~NoSweepScope() | |
| 289 { | |
| 290 ASSERT(m_state->m_sweepInProgress); | |
| 291 m_state->m_sweepInProgress = false; | |
| 292 } | |
| 293 private: | |
| 294 ThreadState* m_state; | |
| 295 }; | |
| 296 | |
| 297 // The set of ThreadStates for all threads attached to the Blink | |
| 298 // garbage collector. | |
| 299 typedef HashSet<ThreadState*> AttachedThreadStateSet; | |
| 300 static AttachedThreadStateSet& attachedThreads(); | |
| 301 | |
| 302 bool isTerminating() { return m_isTerminating; } | |
| 303 | |
| 304 // Trace all persistent roots, called when marking the managed heap objects. | |
| 305 static void visitPersistentRoots(Visitor*); | |
| 306 | |
| 307 // Trace all objects found on the stack, used when doing conservative GCs. | |
| 308 static void visitStackRoots(Visitor*); | |
| 309 | |
| 310 // Associate ThreadState object with the current thread. After this | |
| 311 // call thread can start using the garbage collected heap infrastructure. | |
| 312 // It also has to periodically check for safepoints. | |
| 313 static void attach(); | |
| 314 | |
| 315 // Disassociate attached ThreadState from the current thread. The thread | |
| 316 // can no longer use the garbage collected heap after this call. | |
| 317 static void detach(); | |
| 318 | |
| 319 static ThreadState* mainThreadState() | |
| 320 { | |
| 321 return reinterpret_cast<ThreadState*>(s_mainThreadStateStorage); | |
| 322 } | |
| 323 | |
| 324 bool isMainThread() const { return this == mainThreadState(); } | |
| 325 inline bool checkThread() const | |
| 326 { | |
| 327 ASSERT(m_thread == currentThread()); | |
| 328 return true; | |
| 329 } | |
| 330 | |
| 331 // shouldGC and shouldForceConservativeGC implement the heuristics | |
| 332 // that are used to determine when to collect garbage. If | |
| 333 // shouldForceConservativeGC returns true, we force the garbage | |
| 334 // collection immediately. Otherwise, if shouldGC returns true, we | |
| 335 // record that we should garbage collect the next time we return | |
| 336 // to the event loop. If both return false, we don't need to | |
| 337 // collect garbage at this point. | |
| 338 bool shouldGC(); | |
| 339 bool shouldForceConservativeGC(); | |
| 340 bool increasedEnoughToGC(size_t, size_t); | |
| 341 bool increasedEnoughToForceConservativeGC(size_t, size_t); | |
| 342 | |
| 343 // If gcRequested returns true when a thread returns to its event | |
| 344 // loop the thread will initiate a garbage collection. | |
| 345 bool gcRequested(); | |
| 346 void setGCRequested(); | |
| 347 void clearGCRequested(); | |
| 348 | |
| 349 // Was the last GC forced for testing? This is set when garbage collection | |
| 350 // is forced for testing and there are pointers on the stack. It remains | |
| 351 // set until a garbage collection is triggered with no pointers on the stack
. | |
| 352 // This is used for layout tests that trigger GCs and check if objects are | |
| 353 // dead at a given point in time. That only reliably works when we get | |
| 354 // precise GCs with no conservative stack scanning. | |
| 355 void setForcePreciseGCForTesting(bool); | |
| 356 bool forcePreciseGCForTesting(); | |
| 357 | |
| 358 bool sweepRequested(); | |
| 359 void setSweepRequested(); | |
| 360 void clearSweepRequested(); | |
| 361 void performPendingSweep(); | |
| 362 | |
| 363 // Support for disallowing allocation. Mainly used for sanity | |
| 364 // checks asserts. | |
| 365 bool isAllocationAllowed() const { return !isAtSafePoint() && !m_noAllocatio
nCount; } | |
| 366 void enterNoAllocationScope() { m_noAllocationCount++; } | |
| 367 void leaveNoAllocationScope() { m_noAllocationCount--; } | |
| 368 | |
| 369 // Before performing GC the thread-specific heap state should be | |
| 370 // made consistent for sweeping. | |
| 371 void makeConsistentForSweeping(); | |
| 372 #if ENABLE(ASSERT) | |
| 373 bool isConsistentForSweeping(); | |
| 374 #endif | |
| 375 | |
| 376 // Is the thread corresponding to this thread state currently | |
| 377 // performing GC? | |
| 378 bool isInGC() const { return m_inGC; } | |
| 379 | |
| 380 // Is any of the threads registered with the blink garbage collection | |
| 381 // infrastructure currently performing GC? | |
| 382 static bool isAnyThreadInGC() { return s_inGC; } | |
| 383 | |
| 384 void enterGC() | |
| 385 { | |
| 386 ASSERT(!m_inGC); | |
| 387 ASSERT(!s_inGC); | |
| 388 m_inGC = true; | |
| 389 s_inGC = true; | |
| 390 } | |
| 391 | |
| 392 void leaveGC() | |
| 393 { | |
| 394 m_inGC = false; | |
| 395 s_inGC = false; | |
| 396 } | |
| 397 | |
| 398 // Is the thread corresponding to this thread state currently | |
| 399 // sweeping? | |
| 400 bool isSweepInProgress() const { return m_sweepInProgress; } | |
| 401 | |
| 402 void prepareForGC(); | |
| 403 | |
| 404 // Safepoint related functionality. | |
| 405 // | |
| 406 // When a thread attempts to perform GC it needs to stop all other threads | |
| 407 // that use the heap or at least guarantee that they will not touch any | |
| 408 // heap allocated object until GC is complete. | |
| 409 // | |
| 410 // We say that a thread is at a safepoint if this thread is guaranteed to | |
| 411 // not touch any heap allocated object or any heap related functionality unt
il | |
| 412 // it leaves the safepoint. | |
| 413 // | |
| 414 // Notice that a thread does not have to be paused if it is at safepoint it | |
| 415 // can continue to run and perform tasks that do not require interaction | |
| 416 // with the heap. It will be paused if it attempts to leave the safepoint an
d | |
| 417 // there is a GC in progress. | |
| 418 // | |
| 419 // Each thread that has ThreadState attached must: | |
| 420 // - periodically check if GC is requested from another thread by calling
a safePoint() method; | |
| 421 // - use SafePointScope around long running loops that have no safePoint()
invocation inside, | |
| 422 // such loops must not touch any heap object; | |
| 423 // - register an Interruptor that can interrupt long running loops that ha
ve no calls to safePoint and | |
| 424 // are not wrapped in a SafePointScope (e.g. Interruptor for JavaScript
code) | |
| 425 // | |
| 426 | |
| 427 // Request all other threads to stop. Must only be called if the current thr
ead is at safepoint. | |
| 428 static bool stopThreads(); | |
| 429 static void resumeThreads(); | |
| 430 | |
| 431 // Check if GC is requested by another thread and pause this thread if this
is the case. | |
| 432 // Can only be called when current thread is in a consistent state. | |
| 433 void safePoint(StackState); | |
| 434 | |
| 435 // Mark current thread as running inside safepoint. | |
| 436 void enterSafePointWithoutPointers() { enterSafePoint(NoHeapPointersOnStack,
0); } | |
| 437 void enterSafePointWithPointers(void* scopeMarker) { enterSafePoint(HeapPoin
tersOnStack, scopeMarker); } | |
| 438 void leaveSafePoint(SafePointAwareMutexLocker* = 0); | |
| 439 bool isAtSafePoint() const { return m_atSafePoint; } | |
| 440 | |
| 441 // If attached thread enters long running loop that can call back | |
| 442 // into Blink and leaving and reentering safepoint at every | |
| 443 // transition between this loop and Blink is deemed too expensive | |
| 444 // then instead of marking this loop as a GC safepoint thread | |
| 445 // can provide an interruptor object which would allow GC | |
| 446 // to temporarily interrupt and pause this long running loop at | |
| 447 // an arbitrary moment creating a safepoint for a GC. | |
| 448 class PLATFORM_EXPORT Interruptor { | |
| 449 public: | |
| 450 virtual ~Interruptor() { } | |
| 451 | |
| 452 // Request the interruptor to interrupt the thread and | |
| 453 // call onInterrupted on that thread once interruption | |
| 454 // succeeds. | |
| 455 virtual void requestInterrupt() = 0; | |
| 456 | |
| 457 // Clear previous interrupt request. | |
| 458 virtual void clearInterrupt() = 0; | |
| 459 | |
| 460 protected: | |
| 461 // This method is called on the interrupted thread to | |
| 462 // create a safepoint for a GC. | |
| 463 void onInterrupted(); | |
| 464 }; | |
| 465 | |
| 466 void addInterruptor(Interruptor*); | |
| 467 void removeInterruptor(Interruptor*); | |
| 468 | |
| 469 // CleanupTasks are executed when ThreadState performs | |
| 470 // cleanup before detaching. | |
| 471 class CleanupTask { | |
| 472 public: | |
| 473 virtual ~CleanupTask() { } | |
| 474 | |
| 475 // Executed before the final GC. | |
| 476 virtual void preCleanup() { } | |
| 477 | |
| 478 // Executed after the final GC. Thread heap is empty at this point. | |
| 479 virtual void postCleanup() { } | |
| 480 }; | |
| 481 | |
| 482 void addCleanupTask(PassOwnPtr<CleanupTask> cleanupTask) | |
| 483 { | |
| 484 m_cleanupTasks.append(cleanupTask); | |
| 485 } | |
| 486 | |
| 487 // Should only be called under protection of threadAttachMutex(). | |
| 488 const Vector<Interruptor*>& interruptors() const { return m_interruptors; } | |
| 489 | |
| 490 void recordStackEnd(intptr_t* endOfStack) | |
| 491 { | |
| 492 m_endOfStack = endOfStack; | |
| 493 } | |
| 494 | |
| 495 // Get one of the heap structures for this thread. | |
| 496 // | |
| 497 // The heap is split into multiple heap parts based on object | |
| 498 // types. To get the index for a given type, use | |
| 499 // HeapTypeTrait<Type>::index. | |
| 500 BaseHeap* heap(int index) const { return m_heaps[index]; } | |
| 501 | |
| 502 // Infrastructure to determine if an address is within one of the | |
| 503 // address ranges for the Blink heap. If the address is in the Blink | |
| 504 // heap the containing heap page is returned. | |
| 505 HeapContainsCache* heapContainsCache() { return m_heapContainsCache.get(); } | |
| 506 BaseHeapPage* contains(Address address) { return heapPageFromAddress(address
); } | |
| 507 BaseHeapPage* contains(void* pointer) { return contains(reinterpret_cast<Add
ress>(pointer)); } | |
| 508 BaseHeapPage* contains(const void* pointer) { return contains(const_cast<voi
d*>(pointer)); } | |
| 509 | |
| 510 // List of persistent roots allocated on the given thread. | |
| 511 PersistentNode* roots() const { return m_persistents.get(); } | |
| 512 | |
| 513 // List of global persistent roots not owned by any particular thread. | |
| 514 // globalRootsMutex must be acquired before any modifications. | |
| 515 static PersistentNode* globalRoots(); | |
| 516 static Mutex& globalRootsMutex(); | |
| 517 | |
| 518 // Visit local thread stack and trace all pointers conservatively. | |
| 519 void visitStack(Visitor*); | |
| 520 | |
| 521 // Visit the asan fake stack frame corresponding to a slot on the | |
| 522 // real machine stack if there is one. | |
| 523 void visitAsanFakeStackForPointer(Visitor*, Address); | |
| 524 | |
| 525 // Visit all persistents allocated on this thread. | |
| 526 void visitPersistents(Visitor*); | |
| 527 | |
| 528 // Checks a given address and if a pointer into the oilpan heap marks | |
| 529 // the object to which it points. | |
| 530 bool checkAndMarkPointer(Visitor*, Address); | |
| 531 | |
| 532 #if ENABLE(GC_PROFILE_MARKING) | |
| 533 const GCInfo* findGCInfo(Address); | |
| 534 static const GCInfo* findGCInfoFromAllThreads(Address); | |
| 535 #endif | |
| 536 | |
| 537 #if ENABLE(GC_PROFILE_HEAP) | |
| 538 struct SnapshotInfo { | |
| 539 ThreadState* state; | |
| 540 | |
| 541 size_t freeSize; | |
| 542 size_t pageCount; | |
| 543 | |
| 544 // Map from base-classes to a snapshot class-ids (used as index below). | |
| 545 HashMap<const GCInfo*, size_t> classTags; | |
| 546 | |
| 547 // Map from class-id (index) to count/size. | |
| 548 Vector<int> liveCount; | |
| 549 Vector<int> deadCount; | |
| 550 Vector<size_t> liveSize; | |
| 551 Vector<size_t> deadSize; | |
| 552 | |
| 553 // Map from class-id (index) to a vector of generation counts. | |
| 554 // For i < 7, the count is the number of objects that died after survivi
ng |i| GCs. | |
| 555 // For i == 7, the count is the number of objects that survived at least
7 GCs. | |
| 556 Vector<Vector<int, 8> > generations; | |
| 557 | |
| 558 explicit SnapshotInfo(ThreadState* state) : state(state), freeSize(0), p
ageCount(0) { } | |
| 559 | |
| 560 size_t getClassTag(const GCInfo*); | |
| 561 }; | |
| 562 | |
| 563 void snapshot(); | |
| 564 #endif | |
| 565 | |
| 566 void pushWeakObjectPointerCallback(void*, WeakPointerCallback); | |
| 567 bool popAndInvokeWeakPointerCallback(Visitor*); | |
| 568 | |
| 569 void getStats(HeapStats&); | |
| 570 HeapStats& stats() { return m_stats; } | |
| 571 HeapStats& statsAfterLastGC() { return m_statsAfterLastGC; } | |
| 572 | |
| 573 void setupHeapsForTermination(); | |
| 574 | |
| 575 void registerSweepingTask(); | |
| 576 void unregisterSweepingTask(); | |
| 577 | |
| 578 Mutex& sweepMutex() { return m_sweepMutex; } | |
| 579 | |
| 580 private: | |
| 581 explicit ThreadState(); | |
| 582 ~ThreadState(); | |
| 583 | |
| 584 friend class SafePointBarrier; | |
| 585 | |
| 586 void enterSafePoint(StackState, void*); | |
| 587 NO_SANITIZE_ADDRESS void copyStackUntilSafePointScope(); | |
| 588 void clearSafePointScopeMarker() | |
| 589 { | |
| 590 m_safePointStackCopy.clear(); | |
| 591 m_safePointScopeMarker = 0; | |
| 592 } | |
| 593 | |
| 594 void performPendingGC(StackState); | |
| 595 | |
| 596 // Finds the Blink HeapPage in this thread-specific heap | |
| 597 // corresponding to a given address. Return 0 if the address is | |
| 598 // not contained in any of the pages. This does not consider | |
| 599 // large objects. | |
| 600 BaseHeapPage* heapPageFromAddress(Address); | |
| 601 | |
| 602 // When ThreadState is detaching from non-main thread its | |
| 603 // heap is expected to be empty (because it is going away). | |
| 604 // Perform registered cleanup tasks and garbage collection | |
| 605 // to sweep away any objects that are left on this heap. | |
| 606 // We assert that nothing must remain after this cleanup. | |
| 607 // If assertion does not hold we crash as we are potentially | |
| 608 // in the dangling pointer situation. | |
| 609 void cleanup(); | |
| 610 void cleanupPages(); | |
| 611 | |
| 612 void setLowCollectionRate(bool value) { m_lowCollectionRate = value; } | |
| 613 | |
| 614 void waitUntilSweepersDone(); | |
| 615 | |
| 616 static WTF::ThreadSpecific<ThreadState*>* s_threadSpecific; | |
| 617 static SafePointBarrier* s_safePointBarrier; | |
| 618 | |
| 619 // This variable is flipped to true after all threads are stoped | |
| 620 // and outermost GC has started. | |
| 621 static bool s_inGC; | |
| 622 | |
| 623 // We can't create a static member of type ThreadState here | |
| 624 // because it will introduce global constructor and destructor. | |
| 625 // We would like to manage lifetime of the ThreadState attached | |
| 626 // to the main thread explicitly instead and still use normal | |
| 627 // constructor and destructor for the ThreadState class. | |
| 628 // For this we reserve static storage for the main ThreadState | |
| 629 // and lazily construct ThreadState in it using placement new. | |
| 630 static uint8_t s_mainThreadStateStorage[]; | |
| 631 | |
| 632 ThreadIdentifier m_thread; | |
| 633 OwnPtr<PersistentNode> m_persistents; | |
| 634 StackState m_stackState; | |
| 635 intptr_t* m_startOfStack; | |
| 636 intptr_t* m_endOfStack; | |
| 637 void* m_safePointScopeMarker; | |
| 638 Vector<Address> m_safePointStackCopy; | |
| 639 bool m_atSafePoint; | |
| 640 Vector<Interruptor*> m_interruptors; | |
| 641 bool m_gcRequested; | |
| 642 bool m_forcePreciseGCForTesting; | |
| 643 volatile int m_sweepRequested; | |
| 644 bool m_sweepInProgress; | |
| 645 size_t m_noAllocationCount; | |
| 646 bool m_inGC; | |
| 647 BaseHeap* m_heaps[NumberOfHeaps]; | |
| 648 OwnPtr<HeapContainsCache> m_heapContainsCache; | |
| 649 HeapStats m_stats; | |
| 650 HeapStats m_statsAfterLastGC; | |
| 651 | |
| 652 Vector<OwnPtr<CleanupTask> > m_cleanupTasks; | |
| 653 bool m_isTerminating; | |
| 654 | |
| 655 bool m_lowCollectionRate; | |
| 656 | |
| 657 OwnPtr<blink::WebThread> m_sweeperThread; | |
| 658 int m_numberOfSweeperTasks; | |
| 659 Mutex m_sweepMutex; | |
| 660 ThreadCondition m_sweepThreadCondition; | |
| 661 | |
| 662 CallbackStack* m_weakCallbackStack; | |
| 663 | |
| 664 #if defined(ADDRESS_SANITIZER) | |
| 665 void* m_asanFakeStack; | |
| 666 #endif | |
| 667 }; | |
| 668 | |
| 669 template<ThreadAffinity affinity> class ThreadStateFor; | |
| 670 | |
| 671 template<> class ThreadStateFor<MainThreadOnly> { | |
| 672 public: | |
| 673 static ThreadState* state() | |
| 674 { | |
| 675 // This specialization must only be used from the main thread. | |
| 676 return ThreadState::mainThreadState(); | |
| 677 } | |
| 678 }; | |
| 679 | |
| 680 template<> class ThreadStateFor<AnyThread> { | |
| 681 public: | |
| 682 static ThreadState* state() { return 0; } | |
| 683 }; | |
| 684 | |
| 685 // Common header for heap pages. Needs to be defined before class Visitor. | |
| 686 class BaseHeapPage { | |
| 687 public: | |
| 688 BaseHeapPage(PageMemory*, const GCInfo*, ThreadState*); | |
| 689 virtual ~BaseHeapPage() { } | |
| 690 | |
| 691 // Check if the given address points to an object in this | |
| 692 // heap page. If so, find the start of that object and mark it | |
| 693 // using the given Visitor. Otherwise do nothing. The pointer must | |
| 694 // be within the same aligned blinkPageSize as the this-pointer. | |
| 695 // | |
| 696 // This is used during conservative stack scanning to | |
| 697 // conservatively mark all objects that could be referenced from | |
| 698 // the stack. | |
| 699 virtual void checkAndMarkPointer(Visitor*, Address) = 0; | |
| 700 virtual bool contains(Address) = 0; | |
| 701 | |
| 702 #if ENABLE(GC_PROFILE_MARKING) | |
| 703 virtual const GCInfo* findGCInfo(Address) = 0; | |
| 704 #endif | |
| 705 | |
| 706 Address address() { return reinterpret_cast<Address>(this); } | |
| 707 PageMemory* storage() const { return m_storage; } | |
| 708 ThreadState* threadState() const { return m_threadState; } | |
| 709 const GCInfo* gcInfo() { return m_gcInfo; } | |
| 710 virtual bool isLargeObject() { return false; } | |
| 711 virtual void markOrphaned() | |
| 712 { | |
| 713 m_threadState = 0; | |
| 714 m_gcInfo = 0; | |
| 715 m_terminating = false; | |
| 716 m_tracedAfterOrphaned = false; | |
| 717 } | |
| 718 bool orphaned() { return !m_threadState; } | |
| 719 bool terminating() { return m_terminating; } | |
| 720 void setTerminating() { m_terminating = true; } | |
| 721 bool tracedAfterOrphaned() { return m_tracedAfterOrphaned; } | |
| 722 void setTracedAfterOrphaned() { m_tracedAfterOrphaned = true; } | |
| 723 size_t promptlyFreedSize() { return m_promptlyFreedSize; } | |
| 724 void resetPromptlyFreedSize() { m_promptlyFreedSize = 0; } | |
| 725 void addToPromptlyFreedSize(size_t size) { m_promptlyFreedSize += size; } | |
| 726 | |
| 727 private: | |
| 728 PageMemory* m_storage; | |
| 729 const GCInfo* m_gcInfo; | |
| 730 ThreadState* m_threadState; | |
| 731 // Pointer sized integer to ensure proper alignment of the | |
| 732 // HeapPage header. We use some of the bits to determine | |
| 733 // whether the page is part of a terminting thread or | |
| 734 // if the page is traced after being terminated (orphaned). | |
| 735 uintptr_t m_terminating : 1; | |
| 736 uintptr_t m_tracedAfterOrphaned : 1; | |
| 737 uintptr_t m_promptlyFreedSize : 17; // == blinkPageSizeLog2 | |
| 738 }; | |
| 739 | |
| 740 } | |
| 741 | |
| 742 #endif // ThreadState_h | |
| OLD | NEW |