Coverage Report

Created: 2025-10-31 09:06

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