v8  10.1.124 (node 18.2.0)
V8 is Google's open source JavaScript engine
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
visitor.h
Go to the documentation of this file.
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/sentinel-pointer.h"
16 #include "cppgc/source-location.h"
17 #include "cppgc/trace-trait.h"
18 #include "cppgc/type-traits.h"
19 
20 namespace cppgc {
21 
22 namespace internal {
23 template <typename T, typename WeaknessPolicy, typename LocationPolicy,
24  typename CheckingPolicy>
26 template <typename T, typename WeaknessPolicy, typename LocationPolicy,
27  typename CheckingPolicy>
28 class BasicPersistent;
29 class ConservativeTracingVisitor;
30 class VisitorBase;
31 class VisitorFactory;
32 } // namespace internal
33 
34 using WeakCallback = void (*)(const LivenessBroker&, const void*);
35 
36 /**
37  * Visitor passed to trace methods. All managed pointers must have called the
38  * Visitor's trace method on them.
39  *
40  * \code
41  * class Foo final : public GarbageCollected<Foo> {
42  * public:
43  * void Trace(Visitor* visitor) const {
44  * visitor->Trace(foo_);
45  * visitor->Trace(weak_foo_);
46  * }
47  * private:
48  * Member<Foo> foo_;
49  * WeakMember<Foo> weak_foo_;
50  * };
51  * \endcode
52  */
54  public:
55  class Key {
56  private:
57  Key() = default;
58  friend class internal::VisitorFactory;
59  };
60 
61  explicit Visitor(Key) {}
62 
63  virtual ~Visitor() = default;
64 
65  /**
66  * Trace method for raw pointers. Prefer the versions for managed pointers.
67  *
68  * \param member Reference retaining an object.
69  */
70  template <typename T>
71  void Trace(const T* t) {
72  static_assert(sizeof(T), "Pointee type must be fully defined.");
73  static_assert(internal::IsGarbageCollectedOrMixinType<T>::value,
74  "T must be GarbageCollected or GarbageCollectedMixin type");
75  if (!t) {
76  return;
77  }
78  Visit(t, TraceTrait<T>::GetTraceDescriptor(t));
79  }
80 
81  /**
82  * Trace method for Member.
83  *
84  * \param member Member reference retaining an object.
85  */
86  template <typename T>
87  void Trace(const Member<T>& member) {
88  const T* value = member.GetRawAtomic();
90  Trace(value);
91  }
92 
93  /**
94  * Trace method for WeakMember.
95  *
96  * \param weak_member WeakMember reference weakly retaining an object.
97  */
98  template <typename T>
99  void Trace(const WeakMember<T>& weak_member) {
100  static_assert(sizeof(T), "Pointee type must be fully defined.");
101  static_assert(internal::IsGarbageCollectedOrMixinType<T>::value,
102  "T must be GarbageCollected or GarbageCollectedMixin type");
103  static_assert(!internal::IsAllocatedOnCompactableSpace<T>::value,
104  "Weak references to compactable objects are not allowed");
105 
106  const T* value = weak_member.GetRawAtomic();
107 
108  // Bailout assumes that WeakMember emits write barrier.
109  if (!value) {
110  return;
111  }
112 
113  CPPGC_DCHECK(value != kSentinelPointer);
114  VisitWeak(value, TraceTrait<T>::GetTraceDescriptor(value),
115  &HandleWeak<WeakMember<T>>, &weak_member);
116  }
117 
118  /**
119  * Trace method for inlined objects that are not allocated themselves but
120  * otherwise follow managed heap layout and have a Trace() method.
121  *
122  * \param object reference of the inlined object.
123  */
124  template <typename T>
125  void Trace(const T& object) {
126 #if V8_ENABLE_CHECKS
127  // This object is embedded in potentially multiple nested objects. The
128  // outermost object must not be in construction as such objects are (a) not
129  // processed immediately, and (b) only processed conservatively if not
130  // otherwise possible.
131  CheckObjectNotInConstruction(&object);
132 #endif // V8_ENABLE_CHECKS
133  TraceTrait<T>::Trace(this, &object);
134  }
135 
136  /**
137  * Registers a weak callback method on the object of type T. See
138  * LivenessBroker for an usage example.
139  *
140  * \param object of type T specifying a weak callback method.
141  */
142  template <typename T, void (T::*method)(const LivenessBroker&)>
143  void RegisterWeakCallbackMethod(const T* object) {
144  RegisterWeakCallback(&WeakCallbackMethodDelegate<T, method>, object);
145  }
146 
147  /**
148  * Trace method for EphemeronPair.
149  *
150  * \param ephemeron_pair EphemeronPair reference weakly retaining a key object
151  * and strongly retaining a value object in case the key object is alive.
152  */
153  template <typename K, typename V>
154  void Trace(const EphemeronPair<K, V>& ephemeron_pair) {
155  TraceEphemeron(ephemeron_pair.key, &ephemeron_pair.value);
156  RegisterWeakCallbackMethod<EphemeronPair<K, V>,
157  &EphemeronPair<K, V>::ClearValueIfKeyIsDead>(
158  &ephemeron_pair);
159  }
160 
161  /**
162  * Trace method for a single ephemeron. Used for tracing a raw ephemeron in
163  * which the `key` and `value` are kept separately.
164  *
165  * \param weak_member_key WeakMember reference weakly retaining a key object.
166  * \param member_value Member reference with ephemeron semantics.
167  */
168  template <typename KeyType, typename ValueType>
169  void TraceEphemeron(const WeakMember<KeyType>& weak_member_key,
170  const Member<ValueType>* member_value) {
171  const KeyType* key = weak_member_key.GetRawAtomic();
172  if (!key) return;
173 
174  // `value` must always be non-null.
175  CPPGC_DCHECK(member_value);
176  const ValueType* value = member_value->GetRawAtomic();
177  if (!value) return;
178 
179  // KeyType and ValueType may refer to GarbageCollectedMixin.
180  TraceDescriptor value_desc =
181  TraceTrait<ValueType>::GetTraceDescriptor(value);
183  const void* key_base_object_payload =
184  TraceTrait<KeyType>::GetTraceDescriptor(key).base_object_payload;
185  CPPGC_DCHECK(key_base_object_payload);
186 
187  VisitEphemeron(key_base_object_payload, value, value_desc);
188  }
189 
190  /**
191  * Trace method for a single ephemeron. Used for tracing a raw ephemeron in
192  * which the `key` and `value` are kept separately. Note that this overload
193  * is for non-GarbageCollected `value`s that can be traced though.
194  *
195  * \param key `WeakMember` reference weakly retaining a key object.
196  * \param value Reference weakly retaining a value object. Note that
197  * `ValueType` here should not be `Member`. It is expected that
198  * `TraceTrait<ValueType>::GetTraceDescriptor(value)` returns a
199  * `TraceDescriptor` with a null base pointer but a valid trace method.
200  */
201  template <typename KeyType, typename ValueType>
202  void TraceEphemeron(const WeakMember<KeyType>& weak_member_key,
203  const ValueType* value) {
204  static_assert(!IsGarbageCollectedOrMixinTypeV<ValueType>,
205  "garbage-collected types must use WeakMember and Member");
206  const KeyType* key = weak_member_key.GetRawAtomic();
207  if (!key) return;
208 
209  // `value` must always be non-null.
210  CPPGC_DCHECK(value);
211  TraceDescriptor value_desc =
212  TraceTrait<ValueType>::GetTraceDescriptor(value);
213  // `value_desc.base_object_payload` must be null as this override is only
214  // taken for non-garbage-collected values.
216 
217  // KeyType might be a GarbageCollectedMixin.
218  const void* key_base_object_payload =
219  TraceTrait<KeyType>::GetTraceDescriptor(key).base_object_payload;
220  CPPGC_DCHECK(key_base_object_payload);
221 
222  VisitEphemeron(key_base_object_payload, value, value_desc);
223  }
224 
225  /**
226  * Trace method that strongifies a WeakMember.
227  *
228  * \param weak_member WeakMember reference retaining an object.
229  */
230  template <typename T>
231  void TraceStrongly(const WeakMember<T>& weak_member) {
232  const T* value = weak_member.GetRawAtomic();
233  CPPGC_DCHECK(value != kSentinelPointer);
234  Trace(value);
235  }
236 
237  /**
238  * Trace method for weak containers.
239  *
240  * \param object reference of the weak container.
241  * \param callback to be invoked.
242  * \param data custom data that is passed to the callback.
243  */
244  template <typename T>
245  void TraceWeakContainer(const T* object, WeakCallback callback,
246  const void* data) {
247  if (!object) return;
248  VisitWeakContainer(object, TraceTrait<T>::GetTraceDescriptor(object),
249  TraceTrait<T>::GetWeakTraceDescriptor(object), callback,
250  data);
251  }
252 
253  /**
254  * Registers a slot containing a reference to an object allocated on a
255  * compactable space. Such references maybe be arbitrarily moved by the GC.
256  *
257  * \param slot location of reference to object that might be moved by the GC.
258  */
259  template <typename T>
260  void RegisterMovableReference(const T** slot) {
261  static_assert(internal::IsAllocatedOnCompactableSpace<T>::value,
262  "Only references to objects allocated on compactable spaces "
263  "should be registered as movable slots.");
264  static_assert(!IsGarbageCollectedMixinTypeV<T>,
265  "Mixin types do not support compaction.");
266  HandleMovableReference(reinterpret_cast<const void**>(slot));
267  }
268 
269  /**
270  * Registers a weak callback that is invoked during garbage collection.
271  *
272  * \param callback to be invoked.
273  * \param data custom data that is passed to the callback.
274  */
275  virtual void RegisterWeakCallback(WeakCallback callback, const void* data) {}
276 
277  /**
278  * Defers tracing an object from a concurrent thread to the mutator thread.
279  * Should be called by Trace methods of types that are not safe to trace
280  * concurrently.
281  *
282  * \param parameter tells the trace callback which object was deferred.
283  * \param callback to be invoked for tracing on the mutator thread.
284  * \param deferred_size size of deferred object.
285  *
286  * \returns false if the object does not need to be deferred (i.e. currently
287  * traced on the mutator thread) and true otherwise (i.e. currently traced on
288  * a concurrent thread).
289  */
291  const void* parameter, TraceCallback callback, size_t deferred_size) {
292  // By default tracing is not deferred.
293  return false;
294  }
295 
296  protected:
297  virtual void Visit(const void* self, TraceDescriptor) {}
298  virtual void VisitWeak(const void* self, TraceDescriptor, WeakCallback,
299  const void* weak_member) {}
300  virtual void VisitRoot(const void*, TraceDescriptor, const SourceLocation&) {}
301  virtual void VisitWeakRoot(const void* self, TraceDescriptor, WeakCallback,
302  const void* weak_root, const SourceLocation&) {}
303  virtual void VisitEphemeron(const void* key, const void* value,
304  TraceDescriptor value_desc) {}
305  virtual void VisitWeakContainer(const void* self, TraceDescriptor strong_desc,
306  TraceDescriptor weak_desc,
307  WeakCallback callback, const void* data) {}
308  virtual void HandleMovableReference(const void**) {}
309 
310  private:
311  template <typename T, void (T::*method)(const LivenessBroker&)>
312  static void WeakCallbackMethodDelegate(const LivenessBroker& info,
313  const void* self) {
314  // Callback is registered through a potential const Trace method but needs
315  // to be able to modify fields. See HandleWeak.
316  (const_cast<T*>(static_cast<const T*>(self))->*method)(info);
317  }
318 
319  template <typename PointerType>
320  static void HandleWeak(const LivenessBroker& info, const void* object) {
321  const PointerType* weak = static_cast<const PointerType*>(object);
322  auto* raw_ptr = weak->GetFromGC();
323  // Sentinel values are preserved for weak pointers.
324  if (raw_ptr == kSentinelPointer) return;
325  if (!info.IsHeapObjectAlive(raw_ptr)) {
326  weak->ClearFromGC();
327  }
328  }
329 
330  template <typename Persistent,
331  std::enable_if_t<Persistent::IsStrongPersistent::value>* = nullptr>
332  void TraceRoot(const Persistent& p, const SourceLocation& loc) {
333  using PointeeType = typename Persistent::PointeeType;
334  static_assert(sizeof(PointeeType),
335  "Persistent's pointee type must be fully defined");
336  static_assert(internal::IsGarbageCollectedOrMixinType<PointeeType>::value,
337  "Persistent's pointee type must be GarbageCollected or "
338  "GarbageCollectedMixin");
339  auto* ptr = p.GetFromGC();
340  if (!ptr) {
341  return;
342  }
343  VisitRoot(ptr, TraceTrait<PointeeType>::GetTraceDescriptor(ptr), loc);
344  }
345 
346  template <
347  typename WeakPersistent,
348  std::enable_if_t<!WeakPersistent::IsStrongPersistent::value>* = nullptr>
349  void TraceRoot(const WeakPersistent& p, const SourceLocation& loc) {
350  using PointeeType = typename WeakPersistent::PointeeType;
351  static_assert(sizeof(PointeeType),
352  "Persistent's pointee type must be fully defined");
353  static_assert(internal::IsGarbageCollectedOrMixinType<PointeeType>::value,
354  "Persistent's pointee type must be GarbageCollected or "
355  "GarbageCollectedMixin");
356  static_assert(!internal::IsAllocatedOnCompactableSpace<PointeeType>::value,
357  "Weak references to compactable objects are not allowed");
358  auto* ptr = p.GetFromGC();
359  VisitWeakRoot(ptr, TraceTrait<PointeeType>::GetTraceDescriptor(ptr),
360  &HandleWeak<WeakPersistent>, &p, loc);
361  }
362 
363 #if V8_ENABLE_CHECKS
364  void CheckObjectNotInConstruction(const void* address);
365 #endif // V8_ENABLE_CHECKS
366 
367  template <typename T, typename WeaknessPolicy, typename LocationPolicy,
368  typename CheckingPolicy>
370  template <typename T, typename WeaknessPolicy, typename LocationPolicy,
371  typename CheckingPolicy>
372  friend class internal::BasicPersistent;
373  friend class internal::ConservativeTracingVisitor;
374  friend class internal::VisitorBase;
375 };
376 
377 } // namespace cppgc
378 
379 #endif // INCLUDE_CPPGC_VISITOR_H_