1 // Copyright 2020 the V8 project 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 INCLUDE_CPPGC_VISITOR_H_ 6 #define INCLUDE_CPPGC_VISITOR_H_ 7 8 #include "cppgc/custom-space.h" 9 #include "cppgc/ephemeron-pair.h" 10 #include "cppgc/garbage-collected.h" 11 #include "cppgc/internal/logging.h" 12 #include "cppgc/internal/pointer-policies.h" 13 #include "cppgc/liveness-broker.h" 14 #include "cppgc/member.h" 15 #include "cppgc/source-location.h" 16 #include "cppgc/trace-trait.h" 17 #include "cppgc/type-traits.h" 18 19 namespace cppgc { 20 21 namespace internal { 22 template <typename T, typename WeaknessPolicy, typename LocationPolicy, 23 typename CheckingPolicy> 24 class BasicCrossThreadPersistent; 25 template <typename T, typename WeaknessPolicy, typename LocationPolicy, 26 typename CheckingPolicy> 27 class BasicPersistent; 28 class ConservativeTracingVisitor; 29 class VisitorBase; 30 class VisitorFactory; 31 } // namespace internal 32 33 using WeakCallback = void (*)(const LivenessBroker&, const void*); 34 35 /** 36 * Visitor passed to trace methods. All managed pointers must have called the 37 * Visitor's trace method on them. 38 * 39 * \code 40 * class Foo final : public GarbageCollected<Foo> { 41 * public: 42 * void Trace(Visitor* visitor) const { 43 * visitor->Trace(foo_); 44 * visitor->Trace(weak_foo_); 45 * } 46 * private: 47 * Member<Foo> foo_; 48 * WeakMember<Foo> weak_foo_; 49 * }; 50 * \endcode 51 */ 52 class V8_EXPORT Visitor { 53 public: 54 class Key { 55 private: 56 Key() = default; 57 friend class internal::VisitorFactory; 58 }; 59 Visitor(Key)60 explicit Visitor(Key) {} 61 62 virtual ~Visitor() = default; 63 64 /** 65 * Trace method for Member. 66 * 67 * \param member Member reference retaining an object. 68 */ 69 template <typename T> Trace(const Member<T> & member)70 void Trace(const Member<T>& member) { 71 const T* value = member.GetRawAtomic(); 72 CPPGC_DCHECK(value != kSentinelPointer); 73 Trace(value); 74 } 75 76 /** 77 * Trace method for WeakMember. 78 * 79 * \param weak_member WeakMember reference weakly retaining an object. 80 */ 81 template <typename T> Trace(const WeakMember<T> & weak_member)82 void Trace(const WeakMember<T>& weak_member) { 83 static_assert(sizeof(T), "Pointee type must be fully defined."); 84 static_assert(internal::IsGarbageCollectedType<T>::value, 85 "T must be GarbageCollected or GarbageCollectedMixin type"); 86 static_assert(!internal::IsAllocatedOnCompactableSpace<T>::value, 87 "Weak references to compactable objects are not allowed"); 88 89 const T* value = weak_member.GetRawAtomic(); 90 91 // Bailout assumes that WeakMember emits write barrier. 92 if (!value) { 93 return; 94 } 95 96 CPPGC_DCHECK(value != kSentinelPointer); 97 VisitWeak(value, TraceTrait<T>::GetTraceDescriptor(value), 98 &HandleWeak<WeakMember<T>>, &weak_member); 99 } 100 101 /** 102 * Trace method for inlined objects that are not allocated themselves but 103 * otherwise follow managed heap layout and have a Trace() method. 104 * 105 * \param object reference of the inlined object. 106 */ 107 template <typename T> Trace(const T & object)108 void Trace(const T& object) { 109 #if V8_ENABLE_CHECKS 110 // This object is embedded in potentially multiple nested objects. The 111 // outermost object must not be in construction as such objects are (a) not 112 // processed immediately, and (b) only processed conservatively if not 113 // otherwise possible. 114 CheckObjectNotInConstruction(&object); 115 #endif // V8_ENABLE_CHECKS 116 TraceTrait<T>::Trace(this, &object); 117 } 118 119 /** 120 * Registers a weak callback method on the object of type T. See 121 * LivenessBroker for an usage example. 122 * 123 * \param object of type T specifying a weak callback method. 124 */ 125 template <typename T, void (T::*method)(const LivenessBroker&)> RegisterWeakCallbackMethod(const T * object)126 void RegisterWeakCallbackMethod(const T* object) { 127 RegisterWeakCallback(&WeakCallbackMethodDelegate<T, method>, object); 128 } 129 130 /** 131 * Trace method for EphemeronPair. 132 * 133 * \param ephemeron_pair EphemeronPair reference weakly retaining a key object 134 * and strongly retaining a value object in case the key object is alive. 135 */ 136 template <typename K, typename V> Trace(const EphemeronPair<K,V> & ephemeron_pair)137 void Trace(const EphemeronPair<K, V>& ephemeron_pair) { 138 TraceEphemeron(ephemeron_pair.key, ephemeron_pair.value.GetRawAtomic()); 139 } 140 141 /** 142 * Trace method for ephemerons. Used for tracing raw ephemeron in which the 143 * key and value are kept separately. 144 * 145 * \param key WeakMember reference weakly retaining a key object. 146 * \param value Member reference weakly retaining a value object. 147 */ 148 template <typename K, typename V> TraceEphemeron(const WeakMember<K> & key,const V * value)149 void TraceEphemeron(const WeakMember<K>& key, const V* value) { 150 TraceDescriptor value_desc = TraceTrait<V>::GetTraceDescriptor(value); 151 VisitEphemeron(key, value_desc); 152 } 153 154 /** 155 * Trace method that strongifies a WeakMember. 156 * 157 * \param weak_member WeakMember reference retaining an object. 158 */ 159 template <typename T> TraceStrongly(const WeakMember<T> & weak_member)160 void TraceStrongly(const WeakMember<T>& weak_member) { 161 const T* value = weak_member.GetRawAtomic(); 162 CPPGC_DCHECK(value != kSentinelPointer); 163 Trace(value); 164 } 165 166 /** 167 * Trace method for weak containers. 168 * 169 * \param object reference of the weak container. 170 * \param callback to be invoked. 171 * \param data custom data that is passed to the callback. 172 */ 173 template <typename T> TraceWeakContainer(const T * object,WeakCallback callback,const void * data)174 void TraceWeakContainer(const T* object, WeakCallback callback, 175 const void* data) { 176 if (!object) return; 177 VisitWeakContainer(object, TraceTrait<T>::GetTraceDescriptor(object), 178 TraceTrait<T>::GetWeakTraceDescriptor(object), callback, 179 data); 180 } 181 182 /** 183 * Registers a slot containing a reference to an object allocated on a 184 * compactable space. Such references maybe be arbitrarily moved by the GC. 185 * 186 * \param slot location of reference to object that might be moved by the GC. 187 */ 188 template <typename T> RegisterMovableReference(const T ** slot)189 void RegisterMovableReference(const T** slot) { 190 static_assert(internal::IsAllocatedOnCompactableSpace<T>::value, 191 "Only references to objects allocated on compactable spaces " 192 "should be registered as movable slots."); 193 static_assert(!internal::IsGarbageCollectedMixinTypeV<T>, 194 "Mixin types do not support compaction."); 195 HandleMovableReference(reinterpret_cast<const void**>(slot)); 196 } 197 198 /** 199 * Registers a weak callback that is invoked during garbage collection. 200 * 201 * \param callback to be invoked. 202 * \param data custom data that is passed to the callback. 203 */ RegisterWeakCallback(WeakCallback callback,const void * data)204 virtual void RegisterWeakCallback(WeakCallback callback, const void* data) {} 205 206 /** 207 * Defers tracing an object from a concurrent thread to the mutator thread. 208 * Should be called by Trace methods of types that are not safe to trace 209 * concurrently. 210 * 211 * \param parameter tells the trace callback which object was deferred. 212 * \param callback to be invoked for tracing on the mutator thread. 213 * \param deferred_size size of deferred object. 214 * 215 * \returns false if the object does not need to be deferred (i.e. currently 216 * traced on the mutator thread) and true otherwise (i.e. currently traced on 217 * a concurrent thread). 218 */ DeferTraceToMutatorThreadIfConcurrent(const void * parameter,TraceCallback callback,size_t deferred_size)219 virtual V8_WARN_UNUSED_RESULT bool DeferTraceToMutatorThreadIfConcurrent( 220 const void* parameter, TraceCallback callback, size_t deferred_size) { 221 // By default tracing is not deferred. 222 return false; 223 } 224 225 protected: Visit(const void * self,TraceDescriptor)226 virtual void Visit(const void* self, TraceDescriptor) {} VisitWeak(const void * self,TraceDescriptor,WeakCallback,const void * weak_member)227 virtual void VisitWeak(const void* self, TraceDescriptor, WeakCallback, 228 const void* weak_member) {} VisitRoot(const void *,TraceDescriptor,const SourceLocation &)229 virtual void VisitRoot(const void*, TraceDescriptor, const SourceLocation&) {} VisitWeakRoot(const void * self,TraceDescriptor,WeakCallback,const void * weak_root,const SourceLocation &)230 virtual void VisitWeakRoot(const void* self, TraceDescriptor, WeakCallback, 231 const void* weak_root, const SourceLocation&) {} VisitEphemeron(const void * key,TraceDescriptor value_desc)232 virtual void VisitEphemeron(const void* key, TraceDescriptor value_desc) {} VisitWeakContainer(const void * self,TraceDescriptor strong_desc,TraceDescriptor weak_desc,WeakCallback callback,const void * data)233 virtual void VisitWeakContainer(const void* self, TraceDescriptor strong_desc, 234 TraceDescriptor weak_desc, 235 WeakCallback callback, const void* data) {} HandleMovableReference(const void **)236 virtual void HandleMovableReference(const void**) {} 237 238 private: 239 template <typename T, void (T::*method)(const LivenessBroker&)> WeakCallbackMethodDelegate(const LivenessBroker & info,const void * self)240 static void WeakCallbackMethodDelegate(const LivenessBroker& info, 241 const void* self) { 242 // Callback is registered through a potential const Trace method but needs 243 // to be able to modify fields. See HandleWeak. 244 (const_cast<T*>(static_cast<const T*>(self))->*method)(info); 245 } 246 247 template <typename PointerType> HandleWeak(const LivenessBroker & info,const void * object)248 static void HandleWeak(const LivenessBroker& info, const void* object) { 249 const PointerType* weak = static_cast<const PointerType*>(object); 250 // Sentinel values are preserved for weak pointers. 251 if (*weak == kSentinelPointer) return; 252 const auto* raw = weak->Get(); 253 if (!info.IsHeapObjectAlive(raw)) { 254 weak->ClearFromGC(); 255 } 256 } 257 258 template <typename Persistent, 259 std::enable_if_t<Persistent::IsStrongPersistent::value>* = nullptr> TraceRoot(const Persistent & p,const SourceLocation & loc)260 void TraceRoot(const Persistent& p, const SourceLocation& loc) { 261 using PointeeType = typename Persistent::PointeeType; 262 static_assert(sizeof(PointeeType), 263 "Persistent's pointee type must be fully defined"); 264 static_assert(internal::IsGarbageCollectedType<PointeeType>::value, 265 "Persistent's pointee type must be GarbageCollected or " 266 "GarbageCollectedMixin"); 267 if (!p.Get()) { 268 return; 269 } 270 VisitRoot(p.Get(), TraceTrait<PointeeType>::GetTraceDescriptor(p.Get()), 271 loc); 272 } 273 274 template < 275 typename WeakPersistent, 276 std::enable_if_t<!WeakPersistent::IsStrongPersistent::value>* = nullptr> TraceRoot(const WeakPersistent & p,const SourceLocation & loc)277 void TraceRoot(const WeakPersistent& p, const SourceLocation& loc) { 278 using PointeeType = typename WeakPersistent::PointeeType; 279 static_assert(sizeof(PointeeType), 280 "Persistent's pointee type must be fully defined"); 281 static_assert(internal::IsGarbageCollectedType<PointeeType>::value, 282 "Persistent's pointee type must be GarbageCollected or " 283 "GarbageCollectedMixin"); 284 static_assert(!internal::IsAllocatedOnCompactableSpace<PointeeType>::value, 285 "Weak references to compactable objects are not allowed"); 286 VisitWeakRoot(p.Get(), TraceTrait<PointeeType>::GetTraceDescriptor(p.Get()), 287 &HandleWeak<WeakPersistent>, &p, loc); 288 } 289 290 template <typename T> Trace(const T * t)291 void Trace(const T* t) { 292 static_assert(sizeof(T), "Pointee type must be fully defined."); 293 static_assert(internal::IsGarbageCollectedType<T>::value, 294 "T must be GarbageCollected or GarbageCollectedMixin type"); 295 if (!t) { 296 return; 297 } 298 Visit(t, TraceTrait<T>::GetTraceDescriptor(t)); 299 } 300 301 #if V8_ENABLE_CHECKS 302 void CheckObjectNotInConstruction(const void* address); 303 #endif // V8_ENABLE_CHECKS 304 305 template <typename T, typename WeaknessPolicy, typename LocationPolicy, 306 typename CheckingPolicy> 307 friend class internal::BasicCrossThreadPersistent; 308 template <typename T, typename WeaknessPolicy, typename LocationPolicy, 309 typename CheckingPolicy> 310 friend class internal::BasicPersistent; 311 friend class internal::ConservativeTracingVisitor; 312 friend class internal::VisitorBase; 313 }; 314 315 } // namespace cppgc 316 317 #endif // INCLUDE_CPPGC_VISITOR_H_ 318