v8  8.6.395 (node 15.0.1)
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/garbage-collected.h"
9 #include "cppgc/internal/logging.h"
10 #include "cppgc/internal/pointer-policies.h"
11 #include "cppgc/liveness-broker.h"
12 #include "cppgc/member.h"
13 #include "cppgc/source-location.h"
14 #include "cppgc/trace-trait.h"
15 
16 namespace cppgc {
17 
18 namespace internal {
19 template <typename T, typename WeaknessPolicy, typename LocationPolicy,
20  typename CheckingPolicy>
21 class BasicPersistent;
22 class ConservativeTracingVisitor;
23 class VisitorBase;
24 class VisitorFactory;
25 
26 } // namespace internal
27 
28 using WeakCallback = void (*)(const LivenessBroker&, const void*);
29 
30 /**
31  * Visitor passed to trace methods. All managed pointers must have called the
32  * Visitor's trace method on them.
33  *
34  * \code
35  * class Foo final : public GarbageCollected<Foo> {
36  * public:
37  * void Trace(Visitor* visitor) const {
38  * visitor->Trace(foo_);
39  * visitor->Trace(weak_foo_);
40  * }
41  * private:
42  * Member<Foo> foo_;
43  * WeakMember<Foo> weak_foo_;
44  * };
45  * \endcode
46  */
47 class Visitor {
48  public:
49  class Key {
50  private:
51  Key() = default;
52  friend class internal::VisitorFactory;
53  };
54 
55  explicit Visitor(Key) {}
56 
57  virtual ~Visitor() = default;
58 
59  /**
60  * Trace method for Member.
61  *
62  * \param member Member reference retaining an object.
63  */
64  template <typename T>
65  void Trace(const Member<T>& member) {
66  const T* value = member.GetRawAtomic();
68  Trace(value);
69  }
70 
71  /**
72  * Trace method for WeakMember.
73  *
74  * \param weak_member WeakMember reference weakly retaining an object.
75  */
76  template <typename T>
77  void Trace(const WeakMember<T>& weak_member) {
78  static_assert(sizeof(T), "Pointee type must be fully defined.");
79  static_assert(internal::IsGarbageCollectedType<T>::value,
80  "T must be GarbageCollected or GarbageCollectedMixin type");
81 
82  const T* value = weak_member.GetRawAtomic();
83 
84  // Bailout assumes that WeakMember emits write barrier.
85  if (!value) {
86  return;
87  }
88 
89  // TODO(chromium:1056170): DCHECK (or similar) for deleted values as they
90  // should come in at a different path.
91  VisitWeak(value, TraceTrait<T>::GetTraceDescriptor(value),
92  &HandleWeak<WeakMember<T>>, &weak_member);
93  }
94 
95  /**
96  * Trace method for inlined objects that are not allocated themselves but
97  * otherwise follow managed heap layout and have a Trace() method.
98  *
99  * \param object reference of the inlined object.
100  */
101  template <typename T>
102  void Trace(const T& object) {
103 #if V8_ENABLE_CHECKS
104  // This object is embedded in potentially multiple nested objects. The
105  // outermost object must not be in construction as such objects are (a) not
106  // processed immediately, and (b) only processed conservatively if not
107  // otherwise possible.
108  CheckObjectNotInConstruction(&object);
109 #endif // V8_ENABLE_CHECKS
110  TraceTrait<T>::Trace(this, &object);
111  }
112 
113  /**
114  * Registers a weak callback method on the object of type T. See
115  * LivenessBroker for an usage example.
116  *
117  * \param object of type T specifying a weak callback method.
118  */
119  template <typename T, void (T::*method)(const LivenessBroker&)>
120  void RegisterWeakCallbackMethod(const T* object) {
121  RegisterWeakCallback(&WeakCallbackMethodDelegate<T, method>, object);
122  }
123 
124  /**
125  * Registers a weak callback that is invoked during garbage collection.
126  *
127  * \param callback to be invoked.
128  * \param data custom data that is passed to the callback.
129  */
130  virtual void RegisterWeakCallback(WeakCallback callback, const void* data) {}
131 
132  protected:
133  virtual void Visit(const void* self, TraceDescriptor) {}
134  virtual void VisitWeak(const void* self, TraceDescriptor, WeakCallback,
135  const void* weak_member) {}
136  virtual void VisitRoot(const void*, TraceDescriptor) {}
137  virtual void VisitWeakRoot(const void* self, TraceDescriptor, WeakCallback,
138  const void* weak_root) {}
139 
140  private:
141  template <typename T, void (T::*method)(const LivenessBroker&)>
142  static void WeakCallbackMethodDelegate(const LivenessBroker& info,
143  const void* self) {
144  // Callback is registered through a potential const Trace method but needs
145  // to be able to modify fields. See HandleWeak.
146  (const_cast<T*>(static_cast<const T*>(self))->*method)(info);
147  }
148 
149  template <typename PointerType>
150  static void HandleWeak(const LivenessBroker& info, const void* object) {
151  const PointerType* weak = static_cast<const PointerType*>(object);
152  // Sentinel values are preserved for weak pointers.
153  if (*weak == kSentinelPointer) return;
154  const auto* raw = weak->Get();
155  if (!info.IsHeapObjectAlive(raw)) {
156  weak->ClearFromGC();
157  }
158  }
159 
160  template <typename Persistent,
161  std::enable_if_t<Persistent::IsStrongPersistent::value>* = nullptr>
162  void TraceRoot(const Persistent& p, const SourceLocation& loc) {
163  using PointeeType = typename Persistent::PointeeType;
164  static_assert(sizeof(PointeeType),
165  "Persistent's pointee type must be fully defined");
166  static_assert(internal::IsGarbageCollectedType<PointeeType>::value,
167  "Persistent's pointee type must be GarbageCollected or "
168  "GarbageCollectedMixin");
169  if (!p.Get()) {
170  return;
171  }
172  VisitRoot(p.Get(), TraceTrait<PointeeType>::GetTraceDescriptor(p.Get()));
173  }
174 
175  template <
176  typename WeakPersistent,
177  std::enable_if_t<!WeakPersistent::IsStrongPersistent::value>* = nullptr>
178  void TraceRoot(const WeakPersistent& p, const SourceLocation& loc) {
179  using PointeeType = typename WeakPersistent::PointeeType;
180  static_assert(sizeof(PointeeType),
181  "Persistent's pointee type must be fully defined");
182  static_assert(internal::IsGarbageCollectedType<PointeeType>::value,
183  "Persistent's pointee type must be GarbageCollected or "
184  "GarbageCollectedMixin");
185  VisitWeakRoot(p.Get(), TraceTrait<PointeeType>::GetTraceDescriptor(p.Get()),
186  &HandleWeak<WeakPersistent>, &p);
187  }
188 
189  template <typename T>
190  void Trace(const T* t) {
191  static_assert(sizeof(T), "Pointee type must be fully defined.");
192  static_assert(internal::IsGarbageCollectedType<T>::value,
193  "T must be GarbageCollected or GarbageCollectedMixin type");
194  if (!t) {
195  return;
196  }
197  Visit(t, TraceTrait<T>::GetTraceDescriptor(t));
198  }
199 
200 #if V8_ENABLE_CHECKS
202 #endif // V8_ENABLE_CHECKS
203 
204  template <typename T, typename WeaknessPolicy, typename LocationPolicy,
205  typename CheckingPolicy>
206  friend class internal::BasicPersistent;
207  friend class internal::ConservativeTracingVisitor;
208  friend class internal::VisitorBase;
209 };
210 
211 } // namespace cppgc
212 
213 #endif // INCLUDE_CPPGC_VISITOR_H_