| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #ifndef TraceTraits_h |
| 6 #define TraceTraits_h |
| 7 |
| 8 #include "platform/heap/GCInfo.h" |
| 9 #include "platform/heap/Heap.h" |
| 10 #include "platform/heap/Visitor.h" |
| 11 #include "wtf/Assertions.h" |
| 12 #include "wtf/Deque.h" |
| 13 #include "wtf/HashCountedSet.h" |
| 14 #include "wtf/HashMap.h" |
| 15 #include "wtf/HashSet.h" |
| 16 #include "wtf/HashTable.h" |
| 17 #include "wtf/LinkedHashSet.h" |
| 18 #include "wtf/ListHashSet.h" |
| 19 #include "wtf/TypeTraits.h" |
| 20 #include "wtf/Vector.h" |
| 21 |
| 22 namespace blink { |
| 23 |
| 24 template<typename T> class CrossThreadPersistent; |
| 25 template<typename T> struct GCInfoTrait; |
| 26 class HeapObjectHeader; |
| 27 template<typename T> class Member; |
| 28 template<typename T, bool> class NeedsAdjustAndMark; |
| 29 template<typename T> class TraceTrait; |
| 30 template<typename T> class WeakMember; |
| 31 |
| 32 template<typename T, bool = NeedsAdjustAndMark<T>::value> class DefaultTraceTrai
t; |
| 33 |
| 34 template<typename T> |
| 35 class DefaultTraceTrait<T, false> { |
| 36 public: |
| 37 template<typename VisitorDispatcher> |
| 38 static void mark(VisitorDispatcher visitor, const T* t) |
| 39 { |
| 40 // Default mark method of the trait just calls the two-argument mark |
| 41 // method on the visitor. The second argument is the static trace method |
| 42 // of the trait, which by default calls the instance method |
| 43 // trace(Visitor*) on the object. |
| 44 // |
| 45 // If the trait allows it, invoke the trace callback right here on the |
| 46 // not-yet-marked object. |
| 47 if (TraceEagerlyTrait<T>::value) { |
| 48 // Protect against too deep trace call chains, and the |
| 49 // unbounded system stack usage they can bring about. |
| 50 // |
| 51 // Assert against deep stacks so as to flush them out, |
| 52 // but test and appropriately handle them should they occur |
| 53 // in release builds. |
| 54 // |
| 55 // ASan adds extra stack usage, so disable the assert when it is |
| 56 // enabled so as to avoid testing against a much lower & too low, |
| 57 // stack depth threshold. |
| 58 #if !defined(ADDRESS_SANITIZER) |
| 59 ASSERT(StackFrameDepth::isSafeToRecurse()); |
| 60 #endif |
| 61 if (LIKELY(StackFrameDepth::isSafeToRecurse())) { |
| 62 if (visitor->ensureMarked(t)) { |
| 63 TraceTrait<T>::trace(visitor, const_cast<T*>(t)); |
| 64 } |
| 65 return; |
| 66 } |
| 67 } |
| 68 visitor->mark(const_cast<T*>(t), &TraceTrait<T>::trace); |
| 69 } |
| 70 |
| 71 #if ENABLE(ASSERT) |
| 72 static void checkGCInfo(const T* t) |
| 73 { |
| 74 assertObjectHasGCInfo(const_cast<T*>(t), GCInfoTrait<T>::index()); |
| 75 } |
| 76 #endif |
| 77 }; |
| 78 |
| 79 template<typename T> |
| 80 class DefaultTraceTrait<T, true> { |
| 81 public: |
| 82 template<typename VisitorDispatcher> |
| 83 static void mark(VisitorDispatcher visitor, const T* self) |
| 84 { |
| 85 if (!self) |
| 86 return; |
| 87 |
| 88 // If you hit this ASSERT, it means that there is a dangling pointer |
| 89 // from a live thread heap to a dead thread heap. We must eliminate |
| 90 // the dangling pointer. |
| 91 // Release builds don't have the ASSERT, but it is OK because |
| 92 // release builds will crash at the following self->adjustAndMark |
| 93 // because all the entries of the orphaned heaps are zeroed out and |
| 94 // thus the item does not have a valid vtable. |
| 95 ASSERT(!pageFromObject(self)->orphaned()); |
| 96 self->adjustAndMark(visitor); |
| 97 } |
| 98 |
| 99 #if ENABLE(ASSERT) |
| 100 static void checkGCInfo(const T*) { } |
| 101 #endif |
| 102 }; |
| 103 |
| 104 template<typename T, bool needsTracing> |
| 105 struct TraceIfEnabled; |
| 106 |
| 107 template<typename T> |
| 108 struct TraceIfEnabled<T, false> { |
| 109 template<typename VisitorDispatcher> |
| 110 static void trace(VisitorDispatcher, T*) { } |
| 111 }; |
| 112 |
| 113 template<typename T> |
| 114 struct TraceIfEnabled<T, true> { |
| 115 template<typename VisitorDispatcher> |
| 116 static void trace(VisitorDispatcher visitor, T* t) |
| 117 { |
| 118 visitor->trace(*t); |
| 119 } |
| 120 }; |
| 121 |
| 122 // The TraceTrait is used to specify how to mark an object pointer and |
| 123 // how to trace all of the pointers in the object. |
| 124 // |
| 125 // By default, the 'trace' method implemented on an object itself is |
| 126 // used to trace the pointers to other heap objects inside the object. |
| 127 // |
| 128 // However, the TraceTrait can be specialized to use a different |
| 129 // implementation. A common case where a TraceTrait specialization is |
| 130 // needed is when multiple inheritance leads to pointers that are not |
| 131 // to the start of the object in the Blink garbage-collected heap. In |
| 132 // that case the pointer has to be adjusted before marking. |
| 133 template<typename T> |
| 134 class TraceTrait { |
| 135 public: |
| 136 static void trace(Visitor*, void* self); |
| 137 static void trace(InlinedGlobalMarkingVisitor, void* self); |
| 138 |
| 139 template<typename VisitorDispatcher> |
| 140 static void mark(VisitorDispatcher visitor, const T* t) |
| 141 { |
| 142 DefaultTraceTrait<T>::mark(visitor, t); |
| 143 } |
| 144 |
| 145 #if ENABLE(ASSERT) |
| 146 static void checkGCInfo(const T* t) |
| 147 { |
| 148 DefaultTraceTrait<T>::checkGCInfo(t); |
| 149 } |
| 150 #endif |
| 151 }; |
| 152 |
| 153 template<typename T> class TraceTrait<const T> : public TraceTrait<T> { }; |
| 154 |
| 155 template<typename T> |
| 156 void TraceTrait<T>::trace(Visitor* visitor, void* self) |
| 157 { |
| 158 if (visitor->isGlobalMarkingVisitor()) { |
| 159 // Switch to inlined global marking dispatch. |
| 160 static_cast<T*>(self)->trace(InlinedGlobalMarkingVisitor(visitor)); |
| 161 } else { |
| 162 static_cast<T*>(self)->trace(visitor); |
| 163 } |
| 164 } |
| 165 |
| 166 template<typename T> |
| 167 void TraceTrait<T>::trace(InlinedGlobalMarkingVisitor visitor, void* self) |
| 168 { |
| 169 static_cast<T*>(self)->trace(visitor); |
| 170 } |
| 171 |
| 172 template<typename T, typename Traits> |
| 173 struct TraceTrait<HeapVectorBacking<T, Traits>> { |
| 174 using Backing = HeapVectorBacking<T, Traits>; |
| 175 |
| 176 template<typename VisitorDispatcher> |
| 177 static void trace(VisitorDispatcher visitor, void* self) |
| 178 { |
| 179 static_assert(!WTF::IsWeak<T>::value, "weakness in HeapVectors and Deque
s are not supported"); |
| 180 if (WTF::ShouldBeTraced<Traits>::value) |
| 181 WTF::TraceInCollectionTrait<WTF::NoWeakHandlingInCollections, WTF::W
eakPointersActWeak, HeapVectorBacking<T, Traits>, void>::trace(visitor, self); |
| 182 } |
| 183 |
| 184 template<typename VisitorDispatcher> |
| 185 static void mark(VisitorDispatcher visitor, const Backing* backing) |
| 186 { |
| 187 visitor->mark(backing, &trace); |
| 188 } |
| 189 static void checkGCInfo(Visitor* visitor, const Backing* backing) |
| 190 { |
| 191 #if ENABLE(ASSERT) |
| 192 assertObjectHasGCInfo(const_cast<Backing*>(backing), GCInfoTrait<Backing
>::index()); |
| 193 #endif |
| 194 } |
| 195 }; |
| 196 |
| 197 // The trace trait for the heap hashtable backing is used when we find a |
| 198 // direct pointer to the backing from the conservative stack scanner. This |
| 199 // normally indicates that there is an ongoing iteration over the table, and so |
| 200 // we disable weak processing of table entries. When the backing is found |
| 201 // through the owning hash table we mark differently, in order to do weak |
| 202 // processing. |
| 203 template<typename Table> |
| 204 struct TraceTrait<HeapHashTableBacking<Table>> { |
| 205 using Backing = HeapHashTableBacking<Table>; |
| 206 using Traits = typename Table::ValueTraits; |
| 207 |
| 208 template<typename VisitorDispatcher> |
| 209 static void trace(VisitorDispatcher visitor, void* self) |
| 210 { |
| 211 if (WTF::ShouldBeTraced<Traits>::value || Traits::weakHandlingFlag == WT
F::WeakHandlingInCollections) |
| 212 WTF::TraceInCollectionTrait<WTF::NoWeakHandlingInCollections, WTF::W
eakPointersActStrong, Backing, void>::trace(visitor, self); |
| 213 } |
| 214 |
| 215 template<typename VisitorDispatcher> |
| 216 static void mark(VisitorDispatcher visitor, const Backing* backing) |
| 217 { |
| 218 if (WTF::ShouldBeTraced<Traits>::value || Traits::weakHandlingFlag == WT
F::WeakHandlingInCollections) |
| 219 visitor->mark(backing, &trace); |
| 220 else |
| 221 visitor->markNoTracing(backing); // If we know the trace function wi
ll do nothing there is no need to call it. |
| 222 } |
| 223 static void checkGCInfo(Visitor* visitor, const Backing* backing) |
| 224 { |
| 225 #if ENABLE(ASSERT) |
| 226 assertObjectHasGCInfo(const_cast<Backing*>(backing), GCInfoTrait<Backing
>::index()); |
| 227 #endif |
| 228 } |
| 229 }; |
| 230 |
| 231 // This trace trait for std::pair will null weak members if their referent is |
| 232 // collected. If you have a collection that contain weakness it does not remove |
| 233 // entries from the collection that contain nulled weak members. |
| 234 template<typename T, typename U> |
| 235 class TraceTrait<std::pair<T, U>> { |
| 236 public: |
| 237 static const bool firstNeedsTracing = WTF::NeedsTracing<T>::value || WTF::Is
Weak<T>::value; |
| 238 static const bool secondNeedsTracing = WTF::NeedsTracing<U>::value || WTF::I
sWeak<U>::value; |
| 239 template<typename VisitorDispatcher> |
| 240 static void trace(VisitorDispatcher visitor, std::pair<T, U>* pair) |
| 241 { |
| 242 TraceIfEnabled<T, firstNeedsTracing>::trace(visitor, &pair->first); |
| 243 TraceIfEnabled<U, secondNeedsTracing>::trace(visitor, &pair->second); |
| 244 } |
| 245 }; |
| 246 |
| 247 // If eager tracing leads to excessively deep |trace()| call chains (and |
| 248 // the system stack usage that this brings), the marker implementation will |
| 249 // switch to using an explicit mark stack. Recursive and deep object graphs |
| 250 // are uncommon for Blink objects. |
| 251 // |
| 252 // A class type can opt out of eager tracing by declaring a TraceEagerlyTrait<> |
| 253 // specialization, mapping the trait's |value| to |false| (see the |
| 254 // WILL_NOT_BE_EAGERLY_TRACED_CLASS() macros below.) For Blink, this is done for |
| 255 // the small set of GCed classes that are directly recursive. |
| 256 // |
| 257 // The TraceEagerlyTrait<T> trait controls whether or not a class |
| 258 // (and its subclasses) should be eagerly traced or not. |
| 259 // |
| 260 // If |TraceEagerlyTrait<T>::value| is |true|, then the marker thread |
| 261 // should invoke |trace()| on not-yet-marked objects deriving from class T |
| 262 // right away, and not queue their trace callbacks on its marker stack, |
| 263 // which it will do if |value| is |false|. |
| 264 // |
| 265 // The trait can be declared to enable/disable eager tracing for a class T |
| 266 // and any of its subclasses, or just to the class T, but none of its |
| 267 // subclasses. |
| 268 // |
| 269 template<typename T> |
| 270 class TraceEagerlyTrait { |
| 271 public: |
| 272 static const bool value = true; |
| 273 }; |
| 274 |
| 275 // Disable eager tracing for TYPE, but not any of its subclasses. |
| 276 #define WILL_NOT_BE_EAGERLY_TRACED_CLASS(TYPE) \ |
| 277 template<> \ |
| 278 class TraceEagerlyTrait<TYPE> { \ |
| 279 public: \ |
| 280 static const bool value = false; \ |
| 281 } |
| 282 |
| 283 template<typename T> |
| 284 class TraceEagerlyTrait<Member<T>> { |
| 285 public: |
| 286 static const bool value = TraceEagerlyTrait<T>::value; |
| 287 }; |
| 288 |
| 289 template<typename T> |
| 290 class TraceEagerlyTrait<WeakMember<T>> { |
| 291 public: |
| 292 static const bool value = TraceEagerlyTrait<T>::value; |
| 293 }; |
| 294 |
| 295 template<typename T> |
| 296 class TraceEagerlyTrait<Persistent<T>> { |
| 297 public: |
| 298 static const bool value = TraceEagerlyTrait<T>::value; |
| 299 }; |
| 300 |
| 301 template<typename T> |
| 302 class TraceEagerlyTrait<CrossThreadPersistent<T>> { |
| 303 public: |
| 304 static const bool value = TraceEagerlyTrait<T>::value; |
| 305 }; |
| 306 |
| 307 template<typename ValueArg, size_t inlineCapacity> class HeapListHashSetAllocato
r; |
| 308 template<typename T, size_t inlineCapacity> |
| 309 class TraceEagerlyTrait<WTF::ListHashSetNode<T, HeapListHashSetAllocator<T, inli
neCapacity>>> { |
| 310 public: |
| 311 static const bool value = false; |
| 312 }; |
| 313 |
| 314 template <typename T> struct RemoveHeapPointerWrapperTypes { |
| 315 using Type = typename WTF::RemoveTemplate<typename WTF::RemoveTemplate<typen
ame WTF::RemoveTemplate<T, Member>::Type, WeakMember>::Type, RawPtr>::Type; |
| 316 }; |
| 317 |
| 318 // FIXME: Oilpan: TraceIfNeeded should be implemented ala: |
| 319 // NeedsTracing<T>::value || IsWeakMember<T>::value. It should not need to test |
| 320 // raw pointer types. To remove these tests, we may need support for |
| 321 // instantiating a template with a RawPtrOrMember'ish template. |
| 322 template<typename T> |
| 323 struct TraceIfNeeded : public TraceIfEnabled<T, WTF::NeedsTracing<T>::value || I
sGarbageCollectedType<typename RemoveHeapPointerWrapperTypes<typename WTF::Remov
ePointer<T>::Type>::Type>::value> { }; |
| 324 |
| 325 } // namespace blink |
| 326 |
| 327 namespace WTF { |
| 328 |
| 329 // Catch-all for types that have a way to trace that don't have special |
| 330 // handling for weakness in collections. This means that if this type |
| 331 // contains WeakMember fields, they will simply be zeroed, but the entry |
| 332 // will not be removed from the collection. This always happens for |
| 333 // things in vectors, which don't currently support special handling of |
| 334 // weak elements. |
| 335 template<ShouldWeakPointersBeMarkedStrongly strongify, typename T, typename Trai
ts> |
| 336 struct TraceInCollectionTrait<NoWeakHandlingInCollections, strongify, T, Traits>
{ |
| 337 template<typename VisitorDispatcher> |
| 338 static bool trace(VisitorDispatcher visitor, T& t) |
| 339 { |
| 340 blink::TraceTrait<T>::trace(visitor, &t); |
| 341 return false; |
| 342 } |
| 343 }; |
| 344 |
| 345 template<ShouldWeakPointersBeMarkedStrongly strongify, typename T, typename Trai
ts> |
| 346 struct TraceInCollectionTrait<NoWeakHandlingInCollections, strongify, blink::Mem
ber<T>, Traits> { |
| 347 template<typename VisitorDispatcher> |
| 348 static bool trace(VisitorDispatcher visitor, blink::Member<T>& t) |
| 349 { |
| 350 blink::TraceTrait<T>::mark(visitor, const_cast<typename RemoveConst<T>::
Type*>(t.get())); |
| 351 return false; |
| 352 } |
| 353 }; |
| 354 |
| 355 // Catch-all for things that have HashTrait support for tracing with weakness. |
| 356 template<ShouldWeakPointersBeMarkedStrongly strongify, typename T, typename Trai
ts> |
| 357 struct TraceInCollectionTrait<WeakHandlingInCollections, strongify, T, Traits> { |
| 358 template<typename VisitorDispatcher> |
| 359 static bool trace(VisitorDispatcher visitor, T& t) |
| 360 { |
| 361 return Traits::traceInCollection(visitor, t, strongify); |
| 362 } |
| 363 }; |
| 364 |
| 365 // Vector backing that needs marking. We don't support weak members in vectors. |
| 366 template<ShouldWeakPointersBeMarkedStrongly strongify, typename T, typename Trai
ts> |
| 367 struct TraceInCollectionTrait<NoWeakHandlingInCollections, strongify, blink::Hea
pVectorBacking<T, Traits>, void> { |
| 368 template<typename VisitorDispatcher> |
| 369 static bool trace(VisitorDispatcher visitor, void* self) |
| 370 { |
| 371 // HeapVectorBacking does not know the exact size of the vector |
| 372 // and just knows the capacity of the vector. Due to the constraint, |
| 373 // HeapVectorBacking can support only the following objects: |
| 374 // |
| 375 // - An object that has a vtable. In this case, HeapVectorBacking |
| 376 // traces only slots that are not zeroed out. This is because if |
| 377 // the object has a vtable, the zeroed slot means that it is |
| 378 // an unused slot (Remember that the unused slots are guaranteed |
| 379 // to be zeroed out by VectorUnusedSlotClearer). |
| 380 // |
| 381 // - An object that can be initialized with memset. In this case, |
| 382 // HeapVectorBacking traces all slots including unused slots. |
| 383 // This is fine because the fact that the object can be initialized |
| 384 // with memset indicates that it is safe to treat the zerod slot |
| 385 // as a valid object. |
| 386 static_assert(!ShouldBeTraced<Traits>::value || Traits::canInitializeWit
hMemset || WTF::IsPolymorphic<T>::value, "HeapVectorBacking doesn't support obje
cts that cannot be initialized with memset."); |
| 387 |
| 388 T* array = reinterpret_cast<T*>(self); |
| 389 blink::HeapObjectHeader* header = blink::HeapObjectHeader::fromPayload(s
elf); |
| 390 // Use the payload size as recorded by the heap to determine how many |
| 391 // elements to trace. |
| 392 size_t length = header->payloadSize() / sizeof(T); |
| 393 if (WTF::IsPolymorphic<T>::value) { |
| 394 for (size_t i = 0; i < length; ++i) { |
| 395 if (blink::vTableInitialized(&array[i])) |
| 396 blink::CollectionBackingTraceTrait<ShouldBeTraced<Traits>::v
alue, Traits::weakHandlingFlag, WeakPointersActStrong, T, Traits>::trace(visitor
, array[i]); |
| 397 } |
| 398 } else { |
| 399 #ifdef ANNOTATE_CONTIGUOUS_CONTAINER |
| 400 // As commented above, HeapVectorBacking can trace unused slots |
| 401 // (which are already zeroed out). |
| 402 ANNOTATE_CHANGE_SIZE(array, length, 0, length); |
| 403 #endif |
| 404 for (size_t i = 0; i < length; ++i) |
| 405 blink::CollectionBackingTraceTrait<ShouldBeTraced<Traits>::value
, Traits::weakHandlingFlag, WeakPointersActStrong, T, Traits>::trace(visitor, ar
ray[i]); |
| 406 } |
| 407 return false; |
| 408 } |
| 409 }; |
| 410 |
| 411 // Almost all hash table backings are visited with this specialization. |
| 412 template<ShouldWeakPointersBeMarkedStrongly strongify, typename Table> |
| 413 struct TraceInCollectionTrait<NoWeakHandlingInCollections, strongify, blink::Hea
pHashTableBacking<Table>, void> { |
| 414 using Value = typename Table::ValueType; |
| 415 using Traits = typename Table::ValueTraits; |
| 416 |
| 417 template<typename VisitorDispatcher> |
| 418 static bool trace(VisitorDispatcher visitor, void* self) |
| 419 { |
| 420 Value* array = reinterpret_cast<Value*>(self); |
| 421 blink::HeapObjectHeader* header = blink::HeapObjectHeader::fromPayload(s
elf); |
| 422 size_t length = header->payloadSize() / sizeof(Value); |
| 423 for (size_t i = 0; i < length; ++i) { |
| 424 if (!HashTableHelper<Value, typename Table::ExtractorType, typename
Table::KeyTraitsType>::isEmptyOrDeletedBucket(array[i])) |
| 425 blink::CollectionBackingTraceTrait<ShouldBeTraced<Traits>::value
, Traits::weakHandlingFlag, strongify, Value, Traits>::trace(visitor, array[i]); |
| 426 } |
| 427 return false; |
| 428 } |
| 429 }; |
| 430 |
| 431 // This specialization of TraceInCollectionTrait is for the backing of |
| 432 // HeapListHashSet. This is for the case that we find a reference to the |
| 433 // backing from the stack. That probably means we have a GC while we are in a |
| 434 // ListHashSet method since normal API use does not put pointers to the backing |
| 435 // on the stack. |
| 436 template<ShouldWeakPointersBeMarkedStrongly strongify, typename NodeContents, si
ze_t inlineCapacity, typename T, typename U, typename V, typename W, typename X,
typename Y> |
| 437 struct TraceInCollectionTrait<NoWeakHandlingInCollections, strongify, blink::Hea
pHashTableBacking<HashTable<ListHashSetNode<NodeContents, blink::HeapListHashSet
Allocator<T, inlineCapacity>>*, U, V, W, X, Y, blink::HeapAllocator>>, void> { |
| 438 using Node = ListHashSetNode<NodeContents, blink::HeapListHashSetAllocator<T
, inlineCapacity>>; |
| 439 using Table = HashTable<Node*, U, V, W, X, Y, blink::HeapAllocator>; |
| 440 |
| 441 template<typename VisitorDispatcher> |
| 442 static bool trace(VisitorDispatcher visitor, void* self) |
| 443 { |
| 444 Node** array = reinterpret_cast<Node**>(self); |
| 445 blink::HeapObjectHeader* header = blink::HeapObjectHeader::fromPayload(s
elf); |
| 446 size_t length = header->payloadSize() / sizeof(Node*); |
| 447 for (size_t i = 0; i < length; ++i) { |
| 448 if (!HashTableHelper<Node*, typename Table::ExtractorType, typename
Table::KeyTraitsType>::isEmptyOrDeletedBucket(array[i])) { |
| 449 traceListHashSetValue(visitor, array[i]->m_value); |
| 450 // Just mark the node without tracing because we already traced |
| 451 // the contents, and there is no need to trace the next and |
| 452 // prev fields since iterating over the hash table backing will |
| 453 // find the whole chain. |
| 454 visitor->markNoTracing(array[i]); |
| 455 } |
| 456 } |
| 457 return false; |
| 458 } |
| 459 }; |
| 460 |
| 461 // Key value pairs, as used in HashMap. To disambiguate template choice we have |
| 462 // to have two versions, first the one with no special weak handling, then the |
| 463 // one with weak handling. |
| 464 template<ShouldWeakPointersBeMarkedStrongly strongify, typename Key, typename Va
lue, typename Traits> |
| 465 struct TraceInCollectionTrait<NoWeakHandlingInCollections, strongify, KeyValuePa
ir<Key, Value>, Traits> { |
| 466 template<typename VisitorDispatcher> |
| 467 static bool trace(VisitorDispatcher visitor, KeyValuePair<Key, Value>& self) |
| 468 { |
| 469 ASSERT(ShouldBeTraced<Traits>::value); |
| 470 blink::CollectionBackingTraceTrait<ShouldBeTraced<typename Traits::KeyTr
aits>::value, NoWeakHandlingInCollections, strongify, Key, typename Traits::KeyT
raits>::trace(visitor, self.key); |
| 471 blink::CollectionBackingTraceTrait<ShouldBeTraced<typename Traits::Value
Traits>::value, NoWeakHandlingInCollections, strongify, Value, typename Traits::
ValueTraits>::trace(visitor, self.value); |
| 472 return false; |
| 473 } |
| 474 }; |
| 475 |
| 476 template<ShouldWeakPointersBeMarkedStrongly strongify, typename Key, typename Va
lue, typename Traits> |
| 477 struct TraceInCollectionTrait<WeakHandlingInCollections, strongify, KeyValuePair
<Key, Value>, Traits> { |
| 478 template<typename VisitorDispatcher> |
| 479 static bool trace(VisitorDispatcher visitor, KeyValuePair<Key, Value>& self) |
| 480 { |
| 481 // This is the core of the ephemeron-like functionality. If there is |
| 482 // weakness on the key side then we first check whether there are |
| 483 // dead weak pointers on that side, and if there are we don't mark the |
| 484 // value side (yet). Conversely if there is weakness on the value side |
| 485 // we check that first and don't mark the key side yet if we find dead |
| 486 // weak pointers. |
| 487 // Corner case: If there is weakness on both the key and value side, |
| 488 // and there are also strong pointers on the both sides then we could |
| 489 // unexpectedly leak. The scenario is that the weak pointer on the key |
| 490 // side is alive, which causes the strong pointer on the key side to be |
| 491 // marked. If that then results in the object pointed to by the weak |
| 492 // pointer on the value side being marked live, then the whole |
| 493 // key-value entry is leaked. To avoid unexpected leaking, we disallow |
| 494 // this case, but if you run into this assert, please reach out to Blink |
| 495 // reviewers, and we may relax it. |
| 496 const bool keyIsWeak = Traits::KeyTraits::weakHandlingFlag == WeakHandli
ngInCollections; |
| 497 const bool valueIsWeak = Traits::ValueTraits::weakHandlingFlag == WeakHa
ndlingInCollections; |
| 498 const bool keyHasStrongRefs = ShouldBeTraced<typename Traits::KeyTraits>
::value; |
| 499 const bool valueHasStrongRefs = ShouldBeTraced<typename Traits::ValueTra
its>::value; |
| 500 static_assert(!keyIsWeak || !valueIsWeak || !keyHasStrongRefs || !valueH
asStrongRefs, "this configuration is disallowed to avoid unexpected leaks"); |
| 501 if ((valueIsWeak && !keyIsWeak) || (valueIsWeak && keyIsWeak && !valueHa
sStrongRefs)) { |
| 502 // Check value first. |
| 503 bool deadWeakObjectsFoundOnValueSide = blink::CollectionBackingTrace
Trait<ShouldBeTraced<typename Traits::ValueTraits>::value, Traits::ValueTraits::
weakHandlingFlag, strongify, Value, typename Traits::ValueTraits>::trace(visitor
, self.value); |
| 504 if (deadWeakObjectsFoundOnValueSide) |
| 505 return true; |
| 506 return blink::CollectionBackingTraceTrait<ShouldBeTraced<typename Tr
aits::KeyTraits>::value, Traits::KeyTraits::weakHandlingFlag, strongify, Key, ty
pename Traits::KeyTraits>::trace(visitor, self.key); |
| 507 } |
| 508 // Check key first. |
| 509 bool deadWeakObjectsFoundOnKeySide = blink::CollectionBackingTraceTrait<
ShouldBeTraced<typename Traits::KeyTraits>::value, Traits::KeyTraits::weakHandli
ngFlag, strongify, Key, typename Traits::KeyTraits>::trace(visitor, self.key); |
| 510 if (deadWeakObjectsFoundOnKeySide) |
| 511 return true; |
| 512 return blink::CollectionBackingTraceTrait<ShouldBeTraced<typename Traits
::ValueTraits>::value, Traits::ValueTraits::weakHandlingFlag, strongify, Value,
typename Traits::ValueTraits>::trace(visitor, self.value); |
| 513 } |
| 514 }; |
| 515 |
| 516 // Nodes used by LinkedHashSet. Again we need two versions to disambiguate the |
| 517 // template. |
| 518 template<ShouldWeakPointersBeMarkedStrongly strongify, typename Value, typename
Allocator, typename Traits> |
| 519 struct TraceInCollectionTrait<NoWeakHandlingInCollections, strongify, LinkedHash
SetNode<Value, Allocator>, Traits> { |
| 520 template<typename VisitorDispatcher> |
| 521 static bool trace(VisitorDispatcher visitor, LinkedHashSetNode<Value, Alloca
tor>& self) |
| 522 { |
| 523 ASSERT(ShouldBeTraced<Traits>::value); |
| 524 return TraceInCollectionTrait<NoWeakHandlingInCollections, strongify, Va
lue, typename Traits::ValueTraits>::trace(visitor, self.m_value); |
| 525 } |
| 526 }; |
| 527 |
| 528 template<ShouldWeakPointersBeMarkedStrongly strongify, typename Value, typename
Allocator, typename Traits> |
| 529 struct TraceInCollectionTrait<WeakHandlingInCollections, strongify, LinkedHashSe
tNode<Value, Allocator>, Traits> { |
| 530 template<typename VisitorDispatcher> |
| 531 static bool trace(VisitorDispatcher visitor, LinkedHashSetNode<Value, Alloca
tor>& self) |
| 532 { |
| 533 return TraceInCollectionTrait<WeakHandlingInCollections, strongify, Valu
e, typename Traits::ValueTraits>::trace(visitor, self.m_value); |
| 534 } |
| 535 }; |
| 536 |
| 537 // ListHashSetNode pointers (a ListHashSet is implemented as a hash table of |
| 538 // these pointers). |
| 539 template<ShouldWeakPointersBeMarkedStrongly strongify, typename Value, size_t in
lineCapacity, typename Traits> |
| 540 struct TraceInCollectionTrait<NoWeakHandlingInCollections, strongify, ListHashSe
tNode<Value, blink::HeapListHashSetAllocator<Value, inlineCapacity>>*, Traits> { |
| 541 using Node = ListHashSetNode<Value, blink::HeapListHashSetAllocator<Value, i
nlineCapacity>>; |
| 542 |
| 543 template<typename VisitorDispatcher> |
| 544 static bool trace(VisitorDispatcher visitor, Node* node) |
| 545 { |
| 546 traceListHashSetValue(visitor, node->m_value); |
| 547 // Just mark the node without tracing because we already traced the |
| 548 // contents, and there is no need to trace the next and prev fields |
| 549 // since iterating over the hash table backing will find the whole |
| 550 // chain. |
| 551 visitor->markNoTracing(node); |
| 552 return false; |
| 553 } |
| 554 }; |
| 555 |
| 556 } // namespace WTF |
| 557 |
| 558 #endif |
| OLD | NEW |