• 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_MEMBER_H_
6 #define INCLUDE_CPPGC_MEMBER_H_
7 
8 #include <atomic>
9 #include <cstddef>
10 #include <type_traits>
11 
12 #include "cppgc/internal/pointer-policies.h"
13 #include "cppgc/type-traits.h"
14 #include "v8config.h"  // NOLINT(build/include_directory)
15 
16 namespace cppgc {
17 
18 class Visitor;
19 
20 namespace internal {
21 
22 class MemberBase {
23  protected:
24   MemberBase() = default;
MemberBase(void * value)25   explicit MemberBase(void* value) : raw_(value) {}
26 
GetRawSlot()27   void** GetRawSlot() const { return &raw_; }
GetRaw()28   void* GetRaw() const { return raw_; }
SetRaw(void * value)29   void SetRaw(void* value) { raw_ = value; }
30 
GetRawAtomic()31   void* GetRawAtomic() const {
32     return reinterpret_cast<const std::atomic<void*>*>(&raw_)->load(
33         std::memory_order_relaxed);
34   }
SetRawAtomic(void * value)35   void SetRawAtomic(void* value) {
36     reinterpret_cast<std::atomic<void*>*>(&raw_)->store(
37         value, std::memory_order_relaxed);
38   }
39 
ClearFromGC()40   void ClearFromGC() const { raw_ = nullptr; }
41 
42  private:
43   mutable void* raw_ = nullptr;
44 };
45 
46 // The basic class from which all Member classes are 'generated'.
47 template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
48           typename CheckingPolicy>
49 class BasicMember final : private MemberBase, private CheckingPolicy {
50  public:
51   using PointeeType = T;
52 
53   constexpr BasicMember() = default;
BasicMember(std::nullptr_t)54   constexpr BasicMember(std::nullptr_t) {}     // NOLINT
BasicMember(SentinelPointer s)55   BasicMember(SentinelPointer s) : MemberBase(s) {}  // NOLINT
BasicMember(T * raw)56   BasicMember(T* raw) : MemberBase(raw) {            // NOLINT
57     InitializingWriteBarrier();
58     this->CheckPointer(Get());
59   }
BasicMember(T & raw)60   BasicMember(T& raw) : BasicMember(&raw) {}  // NOLINT
61   // Copy ctor.
BasicMember(const BasicMember & other)62   BasicMember(const BasicMember& other) : BasicMember(other.Get()) {}
63   // Allow heterogeneous construction.
64   template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag,
65             typename OtherCheckingPolicy,
66             typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicMember(const BasicMember<U,OtherWeaknessTag,OtherBarrierPolicy,OtherCheckingPolicy> & other)67   BasicMember(  // NOLINT
68       const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
69                         OtherCheckingPolicy>& other)
70       : BasicMember(other.Get()) {}
71   // Move ctor.
BasicMember(BasicMember && other)72   BasicMember(BasicMember&& other) noexcept : BasicMember(other.Get()) {
73     other.Clear();
74   }
75   // Allow heterogeneous move construction.
76   template <typename U, typename OtherBarrierPolicy, typename OtherWeaknessTag,
77             typename OtherCheckingPolicy,
78             typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicMember(BasicMember<U,OtherWeaknessTag,OtherBarrierPolicy,OtherCheckingPolicy> && other)79   BasicMember(  // NOLINT
80       BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
81                   OtherCheckingPolicy>&& other) noexcept
82       : BasicMember(other.Get()) {
83     other.Clear();
84   }
85   // Construction from Persistent.
86   template <typename U, typename PersistentWeaknessPolicy,
87             typename PersistentLocationPolicy,
88             typename PersistentCheckingPolicy,
89             typename = std::enable_if_t<std::is_base_of<T, U>::value>>
BasicMember(const BasicPersistent<U,PersistentWeaknessPolicy,PersistentLocationPolicy,PersistentCheckingPolicy> & p)90   BasicMember(  // NOLINT
91       const BasicPersistent<U, PersistentWeaknessPolicy,
92                             PersistentLocationPolicy, PersistentCheckingPolicy>&
93           p)
94       : BasicMember(p.Get()) {}
95 
96   // Copy assignment.
97   BasicMember& operator=(const BasicMember& other) {
98     return operator=(other.Get());
99   }
100   // Allow heterogeneous copy assignment.
101   template <typename U, typename OtherWeaknessTag, typename OtherBarrierPolicy,
102             typename OtherCheckingPolicy,
103             typename = std::enable_if_t<std::is_base_of<T, U>::value>>
104   BasicMember& operator=(
105       const BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
106                         OtherCheckingPolicy>& other) {
107     return operator=(other.Get());
108   }
109   // Move assignment.
110   BasicMember& operator=(BasicMember&& other) noexcept {
111     operator=(other.Get());
112     other.Clear();
113     return *this;
114   }
115   // Heterogeneous move assignment.
116   template <typename U, typename OtherWeaknessTag, typename OtherBarrierPolicy,
117             typename OtherCheckingPolicy,
118             typename = std::enable_if_t<std::is_base_of<T, U>::value>>
119   BasicMember& operator=(BasicMember<U, OtherWeaknessTag, OtherBarrierPolicy,
120                                      OtherCheckingPolicy>&& other) noexcept {
121     operator=(other.Get());
122     other.Clear();
123     return *this;
124   }
125   // Assignment from Persistent.
126   template <typename U, typename PersistentWeaknessPolicy,
127             typename PersistentLocationPolicy,
128             typename PersistentCheckingPolicy,
129             typename = std::enable_if_t<std::is_base_of<T, U>::value>>
130   BasicMember& operator=(
131       const BasicPersistent<U, PersistentWeaknessPolicy,
132                             PersistentLocationPolicy, PersistentCheckingPolicy>&
133           other) {
134     return operator=(other.Get());
135   }
136   BasicMember& operator=(T* other) {
137     SetRawAtomic(other);
138     AssigningWriteBarrier();
139     this->CheckPointer(Get());
140     return *this;
141   }
142   BasicMember& operator=(std::nullptr_t) {
143     Clear();
144     return *this;
145   }
146   BasicMember& operator=(SentinelPointer s) {
147     SetRawAtomic(s);
148     return *this;
149   }
150 
151   template <typename OtherWeaknessTag, typename OtherBarrierPolicy,
152             typename OtherCheckingPolicy>
Swap(BasicMember<T,OtherWeaknessTag,OtherBarrierPolicy,OtherCheckingPolicy> & other)153   void Swap(BasicMember<T, OtherWeaknessTag, OtherBarrierPolicy,
154                         OtherCheckingPolicy>& other) {
155     T* tmp = Get();
156     *this = other;
157     other = tmp;
158   }
159 
160   explicit operator bool() const { return Get(); }
161   operator T*() const { return Get(); }  // NOLINT
162   T* operator->() const { return Get(); }
163   T& operator*() const { return *Get(); }
164 
165   // CFI cast exemption to allow passing SentinelPointer through T* and support
166   // heterogeneous assignments between different Member and Persistent handles
167   // based on their actual types.
Get()168   V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
169     // Executed by the mutator, hence non atomic load.
170     return static_cast<T*>(MemberBase::GetRaw());
171   }
172 
Clear()173   void Clear() { SetRawAtomic(nullptr); }
174 
Release()175   T* Release() {
176     T* result = Get();
177     Clear();
178     return result;
179   }
180 
GetSlotForTesting()181   const T** GetSlotForTesting() const {
182     return reinterpret_cast<const T**>(const_cast<const void**>(GetRawSlot()));
183   }
184 
185  private:
GetRawAtomic()186   T* GetRawAtomic() const {
187     return static_cast<T*>(MemberBase::GetRawAtomic());
188   }
189 
InitializingWriteBarrier()190   void InitializingWriteBarrier() const {
191     WriteBarrierPolicy::InitializingBarrier(GetRawSlot(), GetRaw());
192   }
AssigningWriteBarrier()193   void AssigningWriteBarrier() const {
194     WriteBarrierPolicy::AssigningBarrier(GetRawSlot(), GetRaw());
195   }
196 
ClearFromGC()197   void ClearFromGC() const { MemberBase::ClearFromGC(); }
198 
199   friend class cppgc::Visitor;
200 };
201 
202 template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
203           typename CheckingPolicy1, typename T2, typename WeaknessTag2,
204           typename WriteBarrierPolicy2, typename CheckingPolicy2>
205 bool operator==(
206     BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1> member1,
207     BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2>
208         member2) {
209   return member1.Get() == member2.Get();
210 }
211 
212 template <typename T1, typename WeaknessTag1, typename WriteBarrierPolicy1,
213           typename CheckingPolicy1, typename T2, typename WeaknessTag2,
214           typename WriteBarrierPolicy2, typename CheckingPolicy2>
215 bool operator!=(
216     BasicMember<T1, WeaknessTag1, WriteBarrierPolicy1, CheckingPolicy1> member1,
217     BasicMember<T2, WeaknessTag2, WriteBarrierPolicy2, CheckingPolicy2>
218         member2) {
219   return !(member1 == member2);
220 }
221 
222 template <typename T, typename WriteBarrierPolicy, typename CheckingPolicy>
223 struct IsWeak<
224     internal::BasicMember<T, WeakMemberTag, WriteBarrierPolicy, CheckingPolicy>>
225     : std::true_type {};
226 
227 }  // namespace internal
228 
229 /**
230  * Members are used in classes to contain strong pointers to other garbage
231  * collected objects. All Member fields of a class must be traced in the class'
232  * trace method.
233  */
234 template <typename T>
235 using Member = internal::BasicMember<T, internal::StrongMemberTag,
236                                      internal::DijkstraWriteBarrierPolicy>;
237 
238 /**
239  * WeakMember is similar to Member in that it is used to point to other garbage
240  * collected objects. However instead of creating a strong pointer to the
241  * object, the WeakMember creates a weak pointer, which does not keep the
242  * pointee alive. Hence if all pointers to to a heap allocated object are weak
243  * the object will be garbage collected. At the time of GC the weak pointers
244  * will automatically be set to null.
245  */
246 template <typename T>
247 using WeakMember = internal::BasicMember<T, internal::WeakMemberTag,
248                                          internal::DijkstraWriteBarrierPolicy>;
249 
250 /**
251  * UntracedMember is a pointer to an on-heap object that is not traced for some
252  * reason. Do not use this unless you know what you are doing. Keeping raw
253  * pointers to on-heap objects is prohibited unless used from stack. Pointee
254  * must be kept alive through other means.
255  */
256 template <typename T>
257 using UntracedMember = internal::BasicMember<T, internal::UntracedMemberTag,
258                                              internal::NoWriteBarrierPolicy>;
259 
260 }  // namespace cppgc
261 
262 #endif  // INCLUDE_CPPGC_MEMBER_H_
263