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_INTERNAL_POINTER_POLICIES_H_
6#define INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_
7
8#include <cstdint>
9#include <type_traits>
10
11#include "cppgc/internal/member-storage.h"
12#include "cppgc/internal/write-barrier.h"
13#include "cppgc/sentinel-pointer.h"
14#include "cppgc/source-location.h"
15#include "cppgc/type-traits.h"
16#include "v8config.h"  // NOLINT(build/include_directory)
17
18namespace cppgc {
19namespace internal {
20
21class HeapBase;
22class PersistentRegion;
23class CrossThreadPersistentRegion;
24
25// Tags to distinguish between strong and weak member types.
26class StrongMemberTag;
27class WeakMemberTag;
28class UntracedMemberTag;
29
30struct DijkstraWriteBarrierPolicy {
31  V8_INLINE static void InitializingBarrier(const void*, const void*) {
32    // Since in initializing writes the source object is always white, having no
33    // barrier doesn't break the tri-color invariant.
34  }
35
36  template <WriteBarrierSlotType SlotType>
37  V8_INLINE static void AssigningBarrier(const void* slot, const void* value) {
38#ifdef CPPGC_SLIM_WRITE_BARRIER
39    if (V8_UNLIKELY(WriteBarrier::IsEnabled()))
40      WriteBarrier::CombinedWriteBarrierSlow<SlotType>(slot);
41#else   // !CPPGC_SLIM_WRITE_BARRIER
42    WriteBarrier::Params params;
43    const WriteBarrier::Type type =
44        WriteBarrier::GetWriteBarrierType(slot, value, params);
45    WriteBarrier(type, params, slot, value);
46#endif  // !CPPGC_SLIM_WRITE_BARRIER
47  }
48
49  template <WriteBarrierSlotType SlotType>
50  V8_INLINE static void AssigningBarrier(const void* slot, RawPointer storage) {
51    static_assert(
52        SlotType == WriteBarrierSlotType::kUncompressed,
53        "Assigning storages of Member and UncompressedMember is not supported");
54#ifdef CPPGC_SLIM_WRITE_BARRIER
55    if (V8_UNLIKELY(WriteBarrier::IsEnabled()))
56      WriteBarrier::CombinedWriteBarrierSlow<SlotType>(slot);
57#else   // !CPPGC_SLIM_WRITE_BARRIER
58    WriteBarrier::Params params;
59    const WriteBarrier::Type type =
60        WriteBarrier::GetWriteBarrierType(slot, storage, params);
61    WriteBarrier(type, params, slot, storage.Load());
62#endif  // !CPPGC_SLIM_WRITE_BARRIER
63  }
64
65#if defined(CPPGC_POINTER_COMPRESSION)
66  template <WriteBarrierSlotType SlotType>
67  V8_INLINE static void AssigningBarrier(const void* slot,
68                                         CompressedPointer storage) {
69    static_assert(
70        SlotType == WriteBarrierSlotType::kCompressed,
71        "Assigning storages of Member and UncompressedMember is not supported");
72#ifdef CPPGC_SLIM_WRITE_BARRIER
73    if (V8_UNLIKELY(WriteBarrier::IsEnabled()))
74      WriteBarrier::CombinedWriteBarrierSlow<SlotType>(slot);
75#else   // !CPPGC_SLIM_WRITE_BARRIER
76    WriteBarrier::Params params;
77    const WriteBarrier::Type type =
78        WriteBarrier::GetWriteBarrierType(slot, storage, params);
79    WriteBarrier(type, params, slot, storage.Load());
80#endif  // !CPPGC_SLIM_WRITE_BARRIER
81  }
82#endif  // defined(CPPGC_POINTER_COMPRESSION)
83
84 private:
85  V8_INLINE static void WriteBarrier(WriteBarrier::Type type,
86                                     const WriteBarrier::Params& params,
87                                     const void* slot, const void* value) {
88    switch (type) {
89      case WriteBarrier::Type::kGenerational:
90        WriteBarrier::GenerationalBarrier<
91            WriteBarrier::GenerationalBarrierType::kPreciseSlot>(params, slot);
92        break;
93      case WriteBarrier::Type::kMarking:
94        WriteBarrier::DijkstraMarkingBarrier(params, value);
95        break;
96      case WriteBarrier::Type::kNone:
97        break;
98    }
99  }
100};
101
102struct NoWriteBarrierPolicy {
103  V8_INLINE static void InitializingBarrier(const void*, const void*) {}
104  template <WriteBarrierSlotType>
105  V8_INLINE static void AssigningBarrier(const void*, const void*) {}
106  template <WriteBarrierSlotType, typename MemberStorage>
107  V8_INLINE static void AssigningBarrier(const void*, MemberStorage) {}
108};
109
110class V8_EXPORT SameThreadEnabledCheckingPolicyBase {
111 protected:
112  void CheckPointerImpl(const void* ptr, bool points_to_payload,
113                        bool check_off_heap_assignments);
114
115  const HeapBase* heap_ = nullptr;
116};
117
118template <bool kCheckOffHeapAssignments>
119class V8_EXPORT SameThreadEnabledCheckingPolicy
120    : private SameThreadEnabledCheckingPolicyBase {
121 protected:
122  template <typename T>
123  void CheckPointer(const T* ptr) {
124    if (!ptr || (kSentinelPointer == ptr)) return;
125
126    CheckPointersImplTrampoline<T>::Call(this, ptr);
127  }
128
129 private:
130  template <typename T, bool = IsCompleteV<T>>
131  struct CheckPointersImplTrampoline {
132    static void Call(SameThreadEnabledCheckingPolicy* policy, const T* ptr) {
133      policy->CheckPointerImpl(ptr, false, kCheckOffHeapAssignments);
134    }
135  };
136
137  template <typename T>
138  struct CheckPointersImplTrampoline<T, true> {
139    static void Call(SameThreadEnabledCheckingPolicy* policy, const T* ptr) {
140      policy->CheckPointerImpl(ptr, IsGarbageCollectedTypeV<T>,
141                               kCheckOffHeapAssignments);
142    }
143  };
144};
145
146class DisabledCheckingPolicy {
147 protected:
148  V8_INLINE void CheckPointer(const void*) {}
149};
150
151#ifdef DEBUG
152// Off heap members are not connected to object graph and thus cannot ressurect
153// dead objects.
154using DefaultMemberCheckingPolicy =
155    SameThreadEnabledCheckingPolicy<false /* kCheckOffHeapAssignments*/>;
156using DefaultPersistentCheckingPolicy =
157    SameThreadEnabledCheckingPolicy<true /* kCheckOffHeapAssignments*/>;
158#else   // !DEBUG
159using DefaultMemberCheckingPolicy = DisabledCheckingPolicy;
160using DefaultPersistentCheckingPolicy = DisabledCheckingPolicy;
161#endif  // !DEBUG
162// For CT(W)P neither marking information (for value), nor objectstart bitmap
163// (for slot) are guaranteed to be present because there's no synchronization
164// between heaps after marking.
165using DefaultCrossThreadPersistentCheckingPolicy = DisabledCheckingPolicy;
166
167class KeepLocationPolicy {
168 public:
169  constexpr const SourceLocation& Location() const { return location_; }
170
171 protected:
172  constexpr KeepLocationPolicy() = default;
173  constexpr explicit KeepLocationPolicy(const SourceLocation& location)
174      : location_(location) {}
175
176  // KeepLocationPolicy must not copy underlying source locations.
177  KeepLocationPolicy(const KeepLocationPolicy&) = delete;
178  KeepLocationPolicy& operator=(const KeepLocationPolicy&) = delete;
179
180  // Location of the original moved from object should be preserved.
181  KeepLocationPolicy(KeepLocationPolicy&&) = default;
182  KeepLocationPolicy& operator=(KeepLocationPolicy&&) = default;
183
184 private:
185  SourceLocation location_;
186};
187
188class IgnoreLocationPolicy {
189 public:
190  constexpr SourceLocation Location() const { return {}; }
191
192 protected:
193  constexpr IgnoreLocationPolicy() = default;
194  constexpr explicit IgnoreLocationPolicy(const SourceLocation&) {}
195};
196
197#if CPPGC_SUPPORTS_OBJECT_NAMES
198using DefaultLocationPolicy = KeepLocationPolicy;
199#else
200using DefaultLocationPolicy = IgnoreLocationPolicy;
201#endif
202
203struct StrongPersistentPolicy {
204  using IsStrongPersistent = std::true_type;
205  static V8_EXPORT PersistentRegion& GetPersistentRegion(const void* object);
206};
207
208struct WeakPersistentPolicy {
209  using IsStrongPersistent = std::false_type;
210  static V8_EXPORT PersistentRegion& GetPersistentRegion(const void* object);
211};
212
213struct StrongCrossThreadPersistentPolicy {
214  using IsStrongPersistent = std::true_type;
215  static V8_EXPORT CrossThreadPersistentRegion& GetPersistentRegion(
216      const void* object);
217};
218
219struct WeakCrossThreadPersistentPolicy {
220  using IsStrongPersistent = std::false_type;
221  static V8_EXPORT CrossThreadPersistentRegion& GetPersistentRegion(
222      const void* object);
223};
224
225// Forward declarations setting up the default policies.
226template <typename T, typename WeaknessPolicy,
227          typename LocationPolicy = DefaultLocationPolicy,
228          typename CheckingPolicy = DefaultCrossThreadPersistentCheckingPolicy>
229class BasicCrossThreadPersistent;
230template <typename T, typename WeaknessPolicy,
231          typename LocationPolicy = DefaultLocationPolicy,
232          typename CheckingPolicy = DefaultPersistentCheckingPolicy>
233class BasicPersistent;
234template <typename T, typename WeaknessTag, typename WriteBarrierPolicy,
235          typename CheckingPolicy = DefaultMemberCheckingPolicy,
236          typename StorageType = DefaultMemberStorage>
237class BasicMember;
238
239}  // namespace internal
240
241}  // namespace cppgc
242
243#endif  // INCLUDE_CPPGC_INTERNAL_POINTER_POLICIES_H_
244