| 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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 45 #if ENABLE(GC_PROFILING) | 45 #if ENABLE(GC_PROFILING) |
| 46 #include "wtf/InstanceCounter.h" | 46 #include "wtf/InstanceCounter.h" |
| 47 #include "wtf/text/WTFString.h" | 47 #include "wtf/text/WTFString.h" |
| 48 #endif | 48 #endif |
| 49 | 49 |
| 50 namespace blink { | 50 namespace blink { |
| 51 | 51 |
| 52 template<typename T> class GarbageCollected; | 52 template<typename T> class GarbageCollected; |
| 53 class HeapObjectHeader; | 53 class HeapObjectHeader; |
| 54 class InlinedGlobalMarkingVisitor; | 54 class InlinedGlobalMarkingVisitor; |
| 55 template<typename T> class Member; | 55 template<typename T> class TraceTrait; |
| 56 template<typename T> class CrossThreadPersistent; | 56 template<typename T> class TraceEagerlyTrait; |
| 57 class Visitor; | 57 class Visitor; |
| 58 template<typename T> class WeakMember; | |
| 59 | 58 |
| 60 // The TraceMethodDelegate is used to convert a trace method for type T to a Tra
ceCallback. | 59 // The TraceMethodDelegate is used to convert a trace method for type T to a Tra
ceCallback. |
| 61 // This allows us to pass a type's trace method as a parameter to the Persistent
Node | 60 // This allows us to pass a type's trace method as a parameter to the Persistent
Node |
| 62 // constructor. The PersistentNode constructor needs the specific trace method d
ue an issue | 61 // constructor. The PersistentNode constructor needs the specific trace method d
ue an issue |
| 63 // with the Windows compiler which instantiates even unused variables. This caus
es problems | 62 // with the Windows compiler which instantiates even unused variables. This caus
es problems |
| 64 // in header files where we have only forward declarations of classes. | 63 // in header files where we have only forward declarations of classes. |
| 65 template<typename T, void (T::*method)(Visitor*)> | 64 template<typename T, void (T::*method)(Visitor*)> |
| 66 struct TraceMethodDelegate { | 65 struct TraceMethodDelegate { |
| 67 static void trampoline(Visitor* visitor, void* self) { (reinterpret_cast<T*>
(self)->*method)(visitor); } | 66 static void trampoline(Visitor* visitor, void* self) { (reinterpret_cast<T*>
(self)->*method)(visitor); } |
| 68 }; | 67 }; |
| 69 | 68 |
| 70 template<typename T, bool = WTF::IsSubclassOfTemplate<typename WTF::RemoveConst<
T>::Type, GarbageCollected>::value> class NeedsAdjustAndMark; | |
| 71 | |
| 72 template<typename T> | |
| 73 class NeedsAdjustAndMark<T, true> { | |
| 74 public: | |
| 75 static const bool value = false; | |
| 76 }; | |
| 77 | |
| 78 template <typename T> const bool NeedsAdjustAndMark<T, true>::value; | |
| 79 | |
| 80 template<typename T> | |
| 81 class NeedsAdjustAndMark<T, false> { | |
| 82 public: | |
| 83 static const bool value = IsGarbageCollectedMixin<typename WTF::RemoveConst<
T>::Type>::value; | |
| 84 }; | |
| 85 | |
| 86 template <typename T> const bool NeedsAdjustAndMark<T, false>::value; | |
| 87 | |
| 88 // HasInlinedTraceMethod<T>::value is true for T supporting | 69 // HasInlinedTraceMethod<T>::value is true for T supporting |
| 89 // T::trace(InlinedGlobalMarkingVisitor). | 70 // T::trace(InlinedGlobalMarkingVisitor). |
| 90 // The template works by checking if T::HasInlinedTraceMethodMarker type is | 71 // The template works by checking if T::HasInlinedTraceMethodMarker type is |
| 91 // available using SFINAE. The HasInlinedTraceMethodMarker type is defined | 72 // available using SFINAE. The HasInlinedTraceMethodMarker type is defined |
| 92 // by DECLARE_TRACE and DEFINE_INLINE_TRACE helper macros, which are used to | 73 // by DECLARE_TRACE and DEFINE_INLINE_TRACE helper macros, which are used to |
| 93 // define trace methods supporting both inlined/uninlined tracing. | 74 // define trace methods supporting both inlined/uninlined tracing. |
| 94 template <typename T> | 75 template <typename T> |
| 95 struct HasInlinedTraceMethod { | 76 struct HasInlinedTraceMethod { |
| 96 private: | 77 private: |
| 97 typedef char YesType; | 78 typedef char YesType; |
| 98 struct NoType { | 79 struct NoType { |
| 99 char padding[8]; | 80 char padding[8]; |
| 100 }; | 81 }; |
| 101 | 82 |
| 102 template <typename U> static YesType checkMarker(typename U::HasInlinedTrace
MethodMarker*); | 83 template <typename U> static YesType checkMarker(typename U::HasInlinedTrace
MethodMarker*); |
| 103 template <typename U> static NoType checkMarker(...); | 84 template <typename U> static NoType checkMarker(...); |
| 104 public: | 85 public: |
| 105 static const bool value = sizeof(checkMarker<T>(nullptr)) == sizeof(YesType)
; | 86 static const bool value = sizeof(checkMarker<T>(nullptr)) == sizeof(YesType)
; |
| 106 }; | 87 }; |
| 107 | 88 |
| 108 template<typename T, bool = NeedsAdjustAndMark<T>::value> class DefaultTraceTrai
t; | |
| 109 | |
| 110 // The TraceTrait is used to specify how to mark an object pointer and | |
| 111 // how to trace all of the pointers in the object. | |
| 112 // | |
| 113 // By default, the 'trace' method implemented on an object itself is | |
| 114 // used to trace the pointers to other heap objects inside the object. | |
| 115 // | |
| 116 // However, the TraceTrait can be specialized to use a different | |
| 117 // implementation. A common case where a TraceTrait specialization is | |
| 118 // needed is when multiple inheritance leads to pointers that are not | |
| 119 // to the start of the object in the Blink garbage-collected heap. In | |
| 120 // that case the pointer has to be adjusted before marking. | |
| 121 template<typename T> | |
| 122 class TraceTrait { | |
| 123 public: | |
| 124 static void trace(Visitor*, void* self); | |
| 125 static void trace(InlinedGlobalMarkingVisitor, void* self); | |
| 126 | |
| 127 template<typename VisitorDispatcher> | |
| 128 static void mark(VisitorDispatcher visitor, const T* t) | |
| 129 { | |
| 130 DefaultTraceTrait<T>::mark(visitor, t); | |
| 131 } | |
| 132 | |
| 133 #if ENABLE(ASSERT) | |
| 134 static void checkGCInfo(const T* t) | |
| 135 { | |
| 136 DefaultTraceTrait<T>::checkGCInfo(t); | |
| 137 } | |
| 138 #endif | |
| 139 }; | |
| 140 | |
| 141 template<typename T> class TraceTrait<const T> : public TraceTrait<T> { }; | |
| 142 | |
| 143 #define DECLARE_TRACE_IMPL(maybevirtual) \ | 89 #define DECLARE_TRACE_IMPL(maybevirtual) \ |
| 144 public: \ | 90 public: \ |
| 145 typedef int HasInlinedTraceMethodMarker; \ | 91 typedef int HasInlinedTraceMethodMarker; \ |
| 146 maybevirtual void trace(Visitor*); \ | 92 maybevirtual void trace(Visitor*); \ |
| 147 maybevirtual void trace(InlinedGlobalMarkingVisitor); \ | 93 maybevirtual void trace(InlinedGlobalMarkingVisitor); \ |
| 148 \ | 94 \ |
| 149 private: \ | 95 private: \ |
| 150 template <typename VisitorDispatcher> void traceImpl(VisitorDispatcher); \ | 96 template <typename VisitorDispatcher> void traceImpl(VisitorDispatcher); \ |
| 151 \ | 97 \ |
| 152 public: | 98 public: |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 185 template <typename VisitorDispatcher>
\ | 131 template <typename VisitorDispatcher>
\ |
| 186 inline void traceAfterDispatchImpl(VisitorDispatcher visitor) | 132 inline void traceAfterDispatchImpl(VisitorDispatcher visitor) |
| 187 | 133 |
| 188 #define EMPTY_MACRO_ARGUMENT | 134 #define EMPTY_MACRO_ARGUMENT |
| 189 | 135 |
| 190 #define DECLARE_TRACE() DECLARE_TRACE_IMPL(EMPTY_MACRO_ARGUMENT) | 136 #define DECLARE_TRACE() DECLARE_TRACE_IMPL(EMPTY_MACRO_ARGUMENT) |
| 191 #define DECLARE_VIRTUAL_TRACE() DECLARE_TRACE_IMPL(virtual) | 137 #define DECLARE_VIRTUAL_TRACE() DECLARE_TRACE_IMPL(virtual) |
| 192 #define DEFINE_INLINE_TRACE() DEFINE_INLINE_TRACE_IMPL(EMPTY_MACRO_ARGUMENT) | 138 #define DEFINE_INLINE_TRACE() DEFINE_INLINE_TRACE_IMPL(EMPTY_MACRO_ARGUMENT) |
| 193 #define DEFINE_INLINE_VIRTUAL_TRACE() DEFINE_INLINE_TRACE_IMPL(virtual) | 139 #define DEFINE_INLINE_VIRTUAL_TRACE() DEFINE_INLINE_TRACE_IMPL(virtual) |
| 194 | 140 |
| 195 // If MARKER_EAGER_TRACING is set to 1, a marker thread is allowed | 141 template<typename T, bool = WTF::IsSubclassOfTemplate<typename WTF::RemoveConst<
T>::Type, GarbageCollected>::value> class NeedsAdjustAndMark; |
| 196 // to directly invoke the trace() method of not-as-yet marked objects upon | |
| 197 // marking. If it is set to 0, the |trace()| callback for an object will | |
| 198 // be pushed onto an explicit mark stack, which the marker proceeds to | |
| 199 // iteratively pop and invoke. The eager scheme enables inlining of a trace() | |
| 200 // method inside another, the latter keeps system call stack usage bounded | |
| 201 // and under explicit control. | |
| 202 // | |
| 203 // If eager tracing leads to excessively deep |trace()| call chains (and | |
| 204 // the system stack usage that this brings), the marker implementation will | |
| 205 // switch to using an explicit mark stack. Recursive and deep object graphs | |
| 206 // are uncommon for Blink objects. | |
| 207 // | |
| 208 // A class type can opt out of eager tracing by declaring a TraceEagerlyTrait<> | |
| 209 // specialization, mapping the trait's |value| to |false| (see the | |
| 210 // WILL_NOT_BE_EAGERLY_TRACED_CLASS() macros below.) For Blink, this is done for | |
| 211 // the small set of GCed classes that are directly recursive. | |
| 212 // | |
| 213 // The TraceEagerlyTrait<T> trait controls whether or not a class | |
| 214 // (and its subclasses) should be eagerly traced or not. | |
| 215 // | |
| 216 // If |TraceEagerlyTrait<T>::value| is |true|, then the marker thread | |
| 217 // should invoke |trace()| on not-yet-marked objects deriving from class T | |
| 218 // right away, and not queue their trace callbacks on its marker stack, | |
| 219 // which it will do if |value| is |false|. | |
| 220 // | |
| 221 // The trait can be declared to enable/disable eager tracing for a class T | |
| 222 // and any of its subclasses, or just to the class T, but none of its | |
| 223 // subclasses. | |
| 224 // | |
| 225 template<typename T, typename Enabled = void> | |
| 226 class TraceEagerlyTrait { | |
| 227 public: | |
| 228 static const bool value = true; | |
| 229 }; | |
| 230 | |
| 231 // Disable eager tracing for TYPE, but not any of its subclasses. | |
| 232 #define WILL_NOT_BE_EAGERLY_TRACED_CLASS(TYPE) \ | |
| 233 template<> \ | |
| 234 class TraceEagerlyTrait<TYPE> { \ | |
| 235 public: \ | |
| 236 static const bool value = false; \ | |
| 237 } | |
| 238 | 142 |
| 239 template<typename T> | 143 template<typename T> |
| 240 class TraceEagerlyTrait<Member<T>> { | 144 class NeedsAdjustAndMark<T, true> { |
| 241 public: | |
| 242 static const bool value = TraceEagerlyTrait<T>::value; | |
| 243 }; | |
| 244 | |
| 245 template<typename T> | |
| 246 class TraceEagerlyTrait<WeakMember<T>> { | |
| 247 public: | |
| 248 static const bool value = TraceEagerlyTrait<T>::value; | |
| 249 }; | |
| 250 | |
| 251 template<typename T> | |
| 252 class TraceEagerlyTrait<Persistent<T>> { | |
| 253 public: | |
| 254 static const bool value = TraceEagerlyTrait<T>::value; | |
| 255 }; | |
| 256 | |
| 257 template<typename T> | |
| 258 class TraceEagerlyTrait<CrossThreadPersistent<T>> { | |
| 259 public: | |
| 260 static const bool value = TraceEagerlyTrait<T>::value; | |
| 261 }; | |
| 262 | |
| 263 template<typename ValueArg, size_t inlineCapacity> class HeapListHashSetAllocato
r; | |
| 264 template<typename T, size_t inlineCapacity> | |
| 265 class TraceEagerlyTrait<WTF::ListHashSetNode<T, HeapListHashSetAllocator<T, inli
neCapacity>>> { | |
| 266 public: | 145 public: |
| 267 static const bool value = false; | 146 static const bool value = false; |
| 268 }; | 147 }; |
| 148 template <typename T> const bool NeedsAdjustAndMark<T, true>::value; |
| 149 |
| 150 template<typename T> |
| 151 class NeedsAdjustAndMark<T, false> { |
| 152 public: |
| 153 static const bool value = IsGarbageCollectedMixin<typename WTF::RemoveConst<
T>::Type>::value; |
| 154 }; |
| 155 template <typename T> const bool NeedsAdjustAndMark<T, false>::value; |
| 269 | 156 |
| 270 template<typename T, bool = NeedsAdjustAndMark<T>::value> class ObjectAliveTrait
; | 157 template<typename T, bool = NeedsAdjustAndMark<T>::value> class ObjectAliveTrait
; |
| 271 | 158 |
| 272 template<typename T> | 159 template<typename T> |
| 273 class ObjectAliveTrait<T, false> { | 160 class ObjectAliveTrait<T, false> { |
| 274 public: | 161 public: |
| 275 template<typename VisitorDispatcher> | 162 template<typename VisitorDispatcher> |
| 276 static bool isHeapObjectAlive(VisitorDispatcher visitor, T* obj) | 163 static bool isHeapObjectAlive(VisitorDispatcher visitor, T* obj) |
| 277 { | 164 { |
| 278 return visitor->isMarked(obj); | 165 return visitor->isMarked(obj); |
| (...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 590 | 477 |
| 591 template <typename Derived> | 478 template <typename Derived> |
| 592 template <typename T> | 479 template <typename T> |
| 593 void VisitorHelper<Derived>::handleWeakCell(Visitor* self, void* obj) | 480 void VisitorHelper<Derived>::handleWeakCell(Visitor* self, void* obj) |
| 594 { | 481 { |
| 595 T** cell = reinterpret_cast<T**>(obj); | 482 T** cell = reinterpret_cast<T**>(obj); |
| 596 if (*cell && !self->isHeapObjectAlive(*cell)) | 483 if (*cell && !self->isHeapObjectAlive(*cell)) |
| 597 *cell = nullptr; | 484 *cell = nullptr; |
| 598 } | 485 } |
| 599 | 486 |
| 600 template<typename T> struct GCInfoTrait; | |
| 601 | |
| 602 template<typename T> | |
| 603 class DefaultTraceTrait<T, false> { | |
| 604 public: | |
| 605 template<typename VisitorDispatcher> | |
| 606 static void mark(VisitorDispatcher visitor, const T* t) | |
| 607 { | |
| 608 // Default mark method of the trait just calls the two-argument mark | |
| 609 // method on the visitor. The second argument is the static trace method | |
| 610 // of the trait, which by default calls the instance method | |
| 611 // trace(Visitor*) on the object. | |
| 612 // | |
| 613 // If the trait allows it, invoke the trace callback right here on the | |
| 614 // not-yet-marked object. | |
| 615 if (TraceEagerlyTrait<T>::value) { | |
| 616 // Protect against too deep trace call chains, and the | |
| 617 // unbounded system stack usage they can bring about. | |
| 618 // | |
| 619 // Assert against deep stacks so as to flush them out, | |
| 620 // but test and appropriately handle them should they occur | |
| 621 // in release builds. | |
| 622 // | |
| 623 // ASan adds extra stack usage, so disable the assert when it is | |
| 624 // enabled so as to avoid testing against a much lower & too low, | |
| 625 // stack depth threshold. | |
| 626 #if !defined(ADDRESS_SANITIZER) | |
| 627 ASSERT(StackFrameDepth::isSafeToRecurse()); | |
| 628 #endif | |
| 629 if (LIKELY(StackFrameDepth::isSafeToRecurse())) { | |
| 630 if (visitor->ensureMarked(t)) { | |
| 631 TraceTrait<T>::trace(visitor, const_cast<T*>(t)); | |
| 632 } | |
| 633 return; | |
| 634 } | |
| 635 } | |
| 636 visitor->mark(const_cast<T*>(t), &TraceTrait<T>::trace); | |
| 637 } | |
| 638 | |
| 639 #if ENABLE(ASSERT) | |
| 640 static void checkGCInfo(const T* t) | |
| 641 { | |
| 642 assertObjectHasGCInfo(const_cast<T*>(t), GCInfoTrait<T>::index()); | |
| 643 } | |
| 644 #endif | |
| 645 }; | |
| 646 | |
| 647 template<typename T> | |
| 648 class DefaultTraceTrait<T, true> { | |
| 649 public: | |
| 650 template<typename VisitorDispatcher> | |
| 651 static void mark(VisitorDispatcher visitor, const T* self) | |
| 652 { | |
| 653 if (!self) | |
| 654 return; | |
| 655 | |
| 656 // If you hit this ASSERT, it means that there is a dangling pointer | |
| 657 // from a live thread heap to a dead thread heap. We must eliminate | |
| 658 // the dangling pointer. | |
| 659 // Release builds don't have the ASSERT, but it is OK because | |
| 660 // release builds will crash at the following self->adjustAndMark | |
| 661 // because all the entries of the orphaned heaps are zeroed out and | |
| 662 // thus the item does not have a valid vtable. | |
| 663 ASSERT(!pageFromObject(self)->orphaned()); | |
| 664 self->adjustAndMark(visitor); | |
| 665 } | |
| 666 | |
| 667 #if ENABLE(ASSERT) | |
| 668 static void checkGCInfo(const T*) { } | |
| 669 #endif | |
| 670 }; | |
| 671 | |
| 672 #if ENABLE(GC_PROFILING) | 487 #if ENABLE(GC_PROFILING) |
| 673 template<typename T> | 488 template<typename T> |
| 674 struct TypenameStringTrait { | 489 struct TypenameStringTrait { |
| 675 static const String& get() | 490 static const String& get() |
| 676 { | 491 { |
| 677 DEFINE_STATIC_LOCAL(String, typenameString, (WTF::extractTypeNameFromFun
ctionName(WTF::extractNameFunction<T>()))); | 492 DEFINE_STATIC_LOCAL(String, typenameString, (WTF::extractTypeNameFromFun
ctionName(WTF::extractNameFunction<T>()))); |
| 678 return typenameString; | 493 return typenameString; |
| 679 } | 494 } |
| 680 }; | 495 }; |
| 681 #endif | 496 #endif |
| 682 | 497 |
| 683 } // namespace blink | 498 } // namespace blink |
| 684 | 499 |
| 685 #endif // Visitor_h | 500 #endif // Visitor_h |
| OLD | NEW |