v8  8.6.395 (node 15.0.1)
V8 is Google's open source JavaScript engine
v8-cppgc.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_V8_CPPGC_H_
6 #define INCLUDE_V8_CPPGC_H_
7 
8 #include "cppgc/visitor.h"
9 #include "v8-internal.h" // NOLINT(build/include_directory)
10 #include "v8.h" // NOLINT(build/include_directory)
11 
12 namespace v8 {
13 
14 class Isolate;
15 template <typename T>
16 class JSMember;
17 
18 namespace internal {
19 
20 class JSMemberBaseExtractor;
21 
23  public:
24  /**
25  * Returns true if the reference is empty, i.e., has not been assigned
26  * object.
27  */
28  bool IsEmpty() const { return val_ == nullptr; }
29 
30  /**
31  * Clears the reference. IsEmpty() will return true after this call.
32  */
33  inline void Reset();
34 
35  private:
36  static internal::Address* New(v8::Isolate* isolate,
37  internal::Address* object_slot,
38  internal::Address** this_slot);
39  static void Delete(internal::Address* object);
40  static void Copy(const internal::Address* const* from_slot,
41  internal::Address** to_slot);
42  static void Move(internal::Address** from_slot, internal::Address** to_slot);
43 
44  JSMemberBase() = default;
45 
46  JSMemberBase(v8::Isolate* isolate, internal::Address* object_slot)
47  : val_(New(isolate, object_slot, &val_)) {}
48 
49  inline JSMemberBase& CopyImpl(const JSMemberBase& other);
50  inline JSMemberBase& MoveImpl(JSMemberBase&& other);
51 
52  // val_ points to a GlobalHandles node.
53  internal::Address* val_ = nullptr;
54 
55  template <typename T>
56  friend class v8::JSMember;
57  friend class v8::internal::JSMemberBaseExtractor;
58 };
59 
60 JSMemberBase& JSMemberBase::CopyImpl(const JSMemberBase& other) {
61  if (this != &other) {
62  Reset();
63  if (!other.IsEmpty()) {
64  Copy(&other.val_, &val_);
65  }
66  }
67  return *this;
68 }
69 
70 JSMemberBase& JSMemberBase::MoveImpl(JSMemberBase&& other) {
71  if (this != &other) {
72  // No call to Reset() as Move() will conditionally reset itself when needed,
73  // and otherwise reuse the internal meta data.
74  Move(&other.val_, &val_);
75  }
76  return *this;
77 }
78 
80  if (IsEmpty()) return;
81  Delete(val_);
82  val_ = nullptr;
83 }
84 
85 } // namespace internal
86 
87 /**
88  * A traced handle without destructor that clears the handle. The handle may
89  * only be used in GarbageCollected objects and must be processed in a Trace()
90  * method.
91  */
92 template <typename T>
94  static_assert(std::is_base_of<v8::Value, T>::value,
95  "JSMember only supports references to v8::Value");
96 
97  public:
98  JSMember() = default;
99 
100  template <typename U,
101  typename = std::enable_if_t<std::is_base_of<T, U>::value>>
102  JSMember(Isolate* isolate, Local<U> that)
103  : internal::JSMemberBase(isolate,
104  reinterpret_cast<internal::Address*>(*that)) {}
105 
106  JSMember(const JSMember& other) { CopyImpl(other); }
107 
108  template <typename U,
109  typename = std::enable_if_t<std::is_base_of<T, U>::value>>
110  JSMember(const JSMember<U>& other) { // NOLINT
111  CopyImpl(other);
112  }
113 
114  JSMember(JSMember&& other) { MoveImpl(std::move(other)); }
115 
116  template <typename U,
117  typename = std::enable_if_t<std::is_base_of<T, U>::value>>
118  JSMember(JSMember<U>&& other) { // NOLINT
119  MoveImpl(std::move(other));
120  }
121 
122  JSMember& operator=(const JSMember& other) { return CopyImpl(other); }
123 
124  template <typename U,
125  typename = std::enable_if_t<std::is_base_of<T, U>::value>>
126  JSMember& operator=(const JSMember<U>& other) {
127  return CopyImpl(other);
128  }
129 
130  JSMember& operator=(JSMember&& other) { return MoveImpl(other); }
131 
132  template <typename U,
133  typename = std::enable_if_t<std::is_base_of<T, U>::value>>
134  JSMember& operator=(JSMember<U>&& other) {
135  return MoveImpl(other);
136  }
137 
138  T* operator->() const { return reinterpret_cast<T*>(val_); }
139  T* operator*() const { return reinterpret_cast<T*>(val_); }
140 
141  using internal::JSMemberBase::Reset;
142 
143  template <typename U,
144  typename = std::enable_if_t<std::is_base_of<T, U>::value>>
145  void Set(v8::Isolate* isolate, Local<U> that) {
146  Reset();
147  val_ = New(isolate, reinterpret_cast<internal::Address*>(*that), &val_);
148  }
149 };
150 
151 template <typename T1, typename T2,
152  typename = std::enable_if_t<std::is_base_of<T2, T1>::value ||
153  std::is_base_of<T1, T2>::value>>
154 inline bool operator==(const JSMember<T1>& lhs, const JSMember<T2>& rhs) {
155  v8::internal::Address* a = reinterpret_cast<v8::internal::Address*>(*lhs);
156  v8::internal::Address* b = reinterpret_cast<v8::internal::Address*>(*rhs);
157  if (a == nullptr) return b == nullptr;
158  if (b == nullptr) return false;
159  return *a == *b;
160 }
161 
162 template <typename T1, typename T2,
163  typename = std::enable_if_t<std::is_base_of<T2, T1>::value ||
164  std::is_base_of<T1, T2>::value>>
165 inline bool operator!=(const JSMember<T1>& lhs, const JSMember<T2>& rhs) {
166  return !(lhs == rhs);
167 }
168 
169 template <typename T1, typename T2,
170  typename = std::enable_if_t<std::is_base_of<T2, T1>::value ||
171  std::is_base_of<T1, T2>::value>>
172 inline bool operator==(const JSMember<T1>& lhs, const Local<T2>& rhs) {
173  v8::internal::Address* a = reinterpret_cast<v8::internal::Address*>(*lhs);
174  v8::internal::Address* b = reinterpret_cast<v8::internal::Address*>(*rhs);
175  if (a == nullptr) return b == nullptr;
176  if (b == nullptr) return false;
177  return *a == *b;
178 }
179 
180 template <typename T1, typename T2,
181  typename = std::enable_if_t<std::is_base_of<T2, T1>::value ||
182  std::is_base_of<T1, T2>::value>>
183 inline bool operator==(const Local<T1>& lhs, const JSMember<T2> rhs) {
184  return rhs == lhs;
185 }
186 
187 template <typename T1, typename T2>
188 inline bool operator!=(const JSMember<T1>& lhs, const T2& rhs) {
189  return !(lhs == rhs);
190 }
191 
192 template <typename T1, typename T2>
193 inline bool operator!=(const T1& lhs, const JSMember<T2>& rhs) {
194  return !(lhs == rhs);
195 }
196 
197 class JSVisitor : public cppgc::Visitor {
198  public:
199  explicit JSVisitor(cppgc::Visitor::Key key) : cppgc::Visitor(key) {}
200 
201  template <typename T>
202  void Trace(const JSMember<T>& ref) {
203  if (ref.IsEmpty()) return;
204  Visit(ref);
205  }
206 
207  protected:
208  using cppgc::Visitor::Visit;
209 
210  virtual void Visit(const internal::JSMemberBase& ref) {}
211 };
212 
213 } // namespace v8
214 
215 namespace cppgc {
216 
217 template <typename T>
218 struct TraceTrait<v8::JSMember<T>> {
219  static void Trace(Visitor* visitor, const v8::JSMember<T>* self) {
220  static_cast<v8::JSVisitor*>(visitor)->Trace(*self);
221  }
222 };
223 
224 } // namespace cppgc
225 
226 #endif // INCLUDE_V8_CPPGC_H_