• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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