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