File indexing completed on 2026-07-26 09:14:40
0001
0002
0003
0004
0005 #ifndef INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_
0006 #define INCLUDE_CPPGC_CROSS_THREAD_PERSISTENT_H_
0007
0008 #include <atomic>
0009
0010 #include "cppgc/internal/persistent-node.h"
0011 #include "cppgc/internal/pointer-policies.h"
0012 #include "cppgc/persistent.h"
0013 #include "cppgc/visitor.h"
0014
0015 namespace cppgc {
0016 namespace internal {
0017
0018
0019
0020
0021
0022 class CrossThreadPersistentBase : public PersistentBase {
0023 public:
0024 CrossThreadPersistentBase() = default;
0025 explicit CrossThreadPersistentBase(const void* raw) : PersistentBase(raw) {}
0026
0027 V8_CLANG_NO_SANITIZE("address") const void* GetValueFromGC() const {
0028 return raw_;
0029 }
0030
0031 V8_CLANG_NO_SANITIZE("address")
0032 PersistentNode* GetNodeFromGC() const { return node_; }
0033
0034 V8_CLANG_NO_SANITIZE("address")
0035 void ClearFromGC() const {
0036 raw_ = nullptr;
0037 SetNodeSafe(nullptr);
0038 }
0039
0040
0041
0042 PersistentNode* GetNodeSafe() const {
0043 return reinterpret_cast<std::atomic<PersistentNode*>*>(&node_)->load(
0044 std::memory_order_acquire);
0045 }
0046
0047
0048 V8_CLANG_NO_SANITIZE("address")
0049 void SetNodeSafe(PersistentNode* value) const {
0050 #if defined(__has_feature)
0051 #if __has_feature(address_sanitizer)
0052 #define V8_IS_ASAN 1
0053 #endif
0054 #endif
0055
0056 #ifdef V8_IS_ASAN
0057 __atomic_store(&node_, &value, __ATOMIC_RELEASE);
0058 #else
0059
0060
0061 reinterpret_cast<std::atomic<PersistentNode*>*>(&node_)->store(
0062 value, std::memory_order_release);
0063 #endif
0064
0065 #undef V8_IS_ASAN
0066 }
0067 };
0068
0069 template <typename T, typename WeaknessPolicy, typename LocationPolicy,
0070 typename CheckingPolicy>
0071 class BasicCrossThreadPersistent final : public CrossThreadPersistentBase,
0072 public LocationPolicy,
0073 private WeaknessPolicy,
0074 private CheckingPolicy {
0075 public:
0076 using typename WeaknessPolicy::IsStrongPersistent;
0077 using PointeeType = T;
0078
0079 ~BasicCrossThreadPersistent() {
0080
0081
0082
0083
0084
0085 if (GetNodeSafe()) {
0086 PersistentRegionLock guard;
0087 const void* old_value = GetValue();
0088
0089
0090
0091 if (IsValid(old_value)) {
0092 CrossThreadPersistentRegion& region =
0093 this->GetPersistentRegion(old_value);
0094 region.FreeNode(GetNode());
0095 SetNode(nullptr);
0096 } else {
0097 CPPGC_DCHECK(!GetNode());
0098 }
0099 }
0100
0101
0102
0103 }
0104
0105 BasicCrossThreadPersistent(SourceLocation loc = SourceLocation::Current())
0106 : LocationPolicy(loc) {}
0107
0108 BasicCrossThreadPersistent(std::nullptr_t,
0109 SourceLocation loc = SourceLocation::Current())
0110 : LocationPolicy(loc) {}
0111
0112 BasicCrossThreadPersistent(SentinelPointer s,
0113 SourceLocation loc = SourceLocation::Current())
0114 : CrossThreadPersistentBase(s), LocationPolicy(loc) {}
0115
0116 BasicCrossThreadPersistent(T* raw,
0117 SourceLocation loc = SourceLocation::Current())
0118 : CrossThreadPersistentBase(raw), LocationPolicy(loc) {
0119 if (!IsValid(raw)) return;
0120 PersistentRegionLock guard;
0121 CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw);
0122 SetNode(region.AllocateNode(this, &TraceAsRoot));
0123 this->CheckPointer(raw);
0124 }
0125
0126 class UnsafeCtorTag {
0127 private:
0128 UnsafeCtorTag() = default;
0129 template <typename U, typename OtherWeaknessPolicy,
0130 typename OtherLocationPolicy, typename OtherCheckingPolicy>
0131 friend class BasicCrossThreadPersistent;
0132 };
0133
0134 BasicCrossThreadPersistent(UnsafeCtorTag, T* raw,
0135 SourceLocation loc = SourceLocation::Current())
0136 : CrossThreadPersistentBase(raw), LocationPolicy(loc) {
0137 if (!IsValid(raw)) return;
0138 CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw);
0139 SetNode(region.AllocateNode(this, &TraceAsRoot));
0140 this->CheckPointer(raw);
0141 }
0142
0143 BasicCrossThreadPersistent(T& raw,
0144 SourceLocation loc = SourceLocation::Current())
0145 : BasicCrossThreadPersistent(&raw, loc) {}
0146
0147 template <typename U, typename MemberBarrierPolicy,
0148 typename MemberWeaknessTag, typename MemberCheckingPolicy,
0149 typename MemberStorageType,
0150 typename = std::enable_if_t<std::is_base_of_v<T, U>>>
0151 BasicCrossThreadPersistent(
0152 internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
0153 MemberCheckingPolicy, MemberStorageType>
0154 member,
0155 SourceLocation loc = SourceLocation::Current())
0156 : BasicCrossThreadPersistent(member.Get(), loc) {}
0157
0158 BasicCrossThreadPersistent(const BasicCrossThreadPersistent& other,
0159 SourceLocation loc = SourceLocation::Current())
0160 : BasicCrossThreadPersistent(loc) {
0161
0162 *this = other;
0163 }
0164
0165
0166 template <typename U, typename OtherWeaknessPolicy,
0167 typename OtherLocationPolicy, typename OtherCheckingPolicy,
0168 typename = std::enable_if_t<std::is_base_of_v<T, U>>>
0169 BasicCrossThreadPersistent(const BasicCrossThreadPersistent<
0170 U, OtherWeaknessPolicy, OtherLocationPolicy,
0171 OtherCheckingPolicy>& other,
0172 SourceLocation loc = SourceLocation::Current())
0173 : BasicCrossThreadPersistent(loc) {
0174 *this = other;
0175 }
0176
0177 BasicCrossThreadPersistent(
0178 BasicCrossThreadPersistent&& other,
0179 SourceLocation loc = SourceLocation::Current()) noexcept {
0180
0181 *this = std::move(other);
0182 }
0183
0184 BasicCrossThreadPersistent& operator=(
0185 const BasicCrossThreadPersistent& other) {
0186 PersistentRegionLock guard;
0187 AssignSafe(guard, other.Get());
0188 return *this;
0189 }
0190
0191 template <typename U, typename OtherWeaknessPolicy,
0192 typename OtherLocationPolicy, typename OtherCheckingPolicy,
0193 typename = std::enable_if_t<std::is_base_of_v<T, U>>>
0194 BasicCrossThreadPersistent& operator=(
0195 const BasicCrossThreadPersistent<U, OtherWeaknessPolicy,
0196 OtherLocationPolicy,
0197 OtherCheckingPolicy>& other) {
0198 PersistentRegionLock guard;
0199 AssignSafe(guard, other.Get());
0200 return *this;
0201 }
0202
0203 BasicCrossThreadPersistent& operator=(BasicCrossThreadPersistent&& other) {
0204 if (this == &other) return *this;
0205 Clear();
0206 PersistentRegionLock guard;
0207 PersistentBase::operator=(std::move(other));
0208 LocationPolicy::operator=(std::move(other));
0209 if (!IsValid(GetValue())) return *this;
0210 GetNode()->UpdateOwner(this);
0211 other.SetValue(nullptr);
0212 other.SetNode(nullptr);
0213 this->CheckPointer(Get());
0214 return *this;
0215 }
0216
0217
0218
0219
0220
0221
0222 BasicCrossThreadPersistent& operator=(T* other) {
0223 AssignUnsafe(other);
0224 return *this;
0225 }
0226
0227
0228 template <typename U, typename MemberBarrierPolicy,
0229 typename MemberWeaknessTag, typename MemberCheckingPolicy,
0230 typename MemberStorageType,
0231 typename = std::enable_if_t<std::is_base_of_v<T, U>>>
0232 BasicCrossThreadPersistent& operator=(
0233 internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
0234 MemberCheckingPolicy, MemberStorageType>
0235 member) {
0236 return operator=(member.Get());
0237 }
0238
0239
0240
0241
0242
0243
0244 BasicCrossThreadPersistent& operator=(std::nullptr_t) {
0245 Clear();
0246 return *this;
0247 }
0248
0249
0250
0251
0252
0253
0254 BasicCrossThreadPersistent& operator=(SentinelPointer s) {
0255 PersistentRegionLock guard;
0256 AssignSafe(guard, s);
0257 return *this;
0258 }
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270 V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
0271 return static_cast<T*>(const_cast<void*>(GetValue()));
0272 }
0273
0274
0275
0276
0277 void Clear() {
0278 PersistentRegionLock guard;
0279 AssignSafe(guard, nullptr);
0280 }
0281
0282
0283
0284
0285
0286
0287
0288
0289 T* Release() {
0290 T* result = Get();
0291 Clear();
0292 return result;
0293 }
0294
0295
0296
0297
0298
0299
0300
0301
0302 explicit operator bool() const { return Get(); }
0303
0304
0305
0306
0307
0308
0309
0310
0311 operator T*() const { return Get(); }
0312
0313
0314
0315
0316
0317
0318 T* operator->() const { return Get(); }
0319 T& operator*() const { return *Get(); }
0320
0321 template <typename U, typename OtherWeaknessPolicy = WeaknessPolicy,
0322 typename OtherLocationPolicy = LocationPolicy,
0323 typename OtherCheckingPolicy = CheckingPolicy>
0324 BasicCrossThreadPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
0325 OtherCheckingPolicy>
0326 To() const {
0327 using OtherBasicCrossThreadPersistent =
0328 BasicCrossThreadPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
0329 OtherCheckingPolicy>;
0330 PersistentRegionLock guard;
0331 return OtherBasicCrossThreadPersistent(
0332 typename OtherBasicCrossThreadPersistent::UnsafeCtorTag(),
0333 static_cast<U*>(Get()));
0334 }
0335
0336 template <typename U = T,
0337 typename = std::enable_if_t<!BasicCrossThreadPersistent<
0338 U, WeaknessPolicy>::IsStrongPersistent::value>>
0339 BasicCrossThreadPersistent<U, internal::StrongCrossThreadPersistentPolicy>
0340 Lock() const {
0341 return BasicCrossThreadPersistent<
0342 U, internal::StrongCrossThreadPersistentPolicy>(*this);
0343 }
0344
0345 private:
0346 static bool IsValid(const void* ptr) {
0347 return ptr && ptr != kSentinelPointer;
0348 }
0349
0350 static void TraceAsRoot(RootVisitor& root_visitor, const void* ptr) {
0351 root_visitor.Trace(*static_cast<const BasicCrossThreadPersistent*>(ptr));
0352 }
0353
0354 void AssignUnsafe(T* ptr) {
0355 const void* old_value = GetValue();
0356 if (IsValid(old_value)) {
0357 PersistentRegionLock guard;
0358 old_value = GetValue();
0359
0360
0361 if (IsValid(old_value)) {
0362 CrossThreadPersistentRegion& region =
0363 this->GetPersistentRegion(old_value);
0364 if (IsValid(ptr) && (®ion == &this->GetPersistentRegion(ptr))) {
0365 SetValue(ptr);
0366 this->CheckPointer(ptr);
0367 return;
0368 }
0369 region.FreeNode(GetNode());
0370 SetNode(nullptr);
0371 } else {
0372 CPPGC_DCHECK(!GetNode());
0373 }
0374 }
0375 SetValue(ptr);
0376 if (!IsValid(ptr)) return;
0377 PersistentRegionLock guard;
0378 SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &TraceAsRoot));
0379 this->CheckPointer(ptr);
0380 }
0381
0382 void AssignSafe(PersistentRegionLock&, T* ptr) {
0383 PersistentRegionLock::AssertLocked();
0384 const void* old_value = GetValue();
0385 if (IsValid(old_value)) {
0386 CrossThreadPersistentRegion& region =
0387 this->GetPersistentRegion(old_value);
0388 if (IsValid(ptr) && (®ion == &this->GetPersistentRegion(ptr))) {
0389 SetValue(ptr);
0390 this->CheckPointer(ptr);
0391 return;
0392 }
0393 region.FreeNode(GetNode());
0394 SetNode(nullptr);
0395 }
0396 SetValue(ptr);
0397 if (!IsValid(ptr)) return;
0398 SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &TraceAsRoot));
0399 this->CheckPointer(ptr);
0400 }
0401
0402 void ClearFromGC() const {
0403 if (IsValid(GetValueFromGC())) {
0404 WeaknessPolicy::GetPersistentRegion(GetValueFromGC())
0405 .FreeNode(GetNodeFromGC());
0406 CrossThreadPersistentBase::ClearFromGC();
0407 }
0408 }
0409
0410
0411 V8_CLANG_NO_SANITIZE("cfi-unrelated-cast")
0412 T* GetFromGC() const {
0413 return static_cast<T*>(const_cast<void*>(GetValueFromGC()));
0414 }
0415
0416 friend class internal::RootVisitor;
0417 };
0418
0419 template <typename T, typename LocationPolicy, typename CheckingPolicy>
0420 struct IsWeak<
0421 BasicCrossThreadPersistent<T, internal::WeakCrossThreadPersistentPolicy,
0422 LocationPolicy, CheckingPolicy>>
0423 : std::true_type {};
0424
0425 }
0426
0427 namespace subtle {
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440 template <typename T>
0441 using CrossThreadPersistent = internal::BasicCrossThreadPersistent<
0442 T, internal::StrongCrossThreadPersistentPolicy>;
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455 template <typename T>
0456 using WeakCrossThreadPersistent = internal::BasicCrossThreadPersistent<
0457 T, internal::WeakCrossThreadPersistentPolicy>;
0458
0459 }
0460 }
0461
0462 #endif