File indexing completed on 2025-04-02 08:54:42
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(
0106 const SourceLocation& loc = SourceLocation::Current())
0107 : LocationPolicy(loc) {}
0108
0109 BasicCrossThreadPersistent(
0110 std::nullptr_t, const SourceLocation& loc = SourceLocation::Current())
0111 : LocationPolicy(loc) {}
0112
0113 BasicCrossThreadPersistent(
0114 SentinelPointer s, const SourceLocation& loc = SourceLocation::Current())
0115 : CrossThreadPersistentBase(s), LocationPolicy(loc) {}
0116
0117 BasicCrossThreadPersistent(
0118 T* raw, const SourceLocation& loc = SourceLocation::Current())
0119 : CrossThreadPersistentBase(raw), LocationPolicy(loc) {
0120 if (!IsValid(raw)) return;
0121 PersistentRegionLock guard;
0122 CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw);
0123 SetNode(region.AllocateNode(this, &TraceAsRoot));
0124 this->CheckPointer(raw);
0125 }
0126
0127 class UnsafeCtorTag {
0128 private:
0129 UnsafeCtorTag() = default;
0130 template <typename U, typename OtherWeaknessPolicy,
0131 typename OtherLocationPolicy, typename OtherCheckingPolicy>
0132 friend class BasicCrossThreadPersistent;
0133 };
0134
0135 BasicCrossThreadPersistent(
0136 UnsafeCtorTag, T* raw,
0137 const SourceLocation& loc = SourceLocation::Current())
0138 : CrossThreadPersistentBase(raw), LocationPolicy(loc) {
0139 if (!IsValid(raw)) return;
0140 CrossThreadPersistentRegion& region = this->GetPersistentRegion(raw);
0141 SetNode(region.AllocateNode(this, &TraceAsRoot));
0142 this->CheckPointer(raw);
0143 }
0144
0145 BasicCrossThreadPersistent(
0146 T& raw, const SourceLocation& loc = SourceLocation::Current())
0147 : BasicCrossThreadPersistent(&raw, loc) {}
0148
0149 template <typename U, typename MemberBarrierPolicy,
0150 typename MemberWeaknessTag, typename MemberCheckingPolicy,
0151 typename MemberStorageType,
0152 typename = std::enable_if_t<std::is_base_of<T, U>::value>>
0153 BasicCrossThreadPersistent(
0154 internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
0155 MemberCheckingPolicy, MemberStorageType>
0156 member,
0157 const SourceLocation& loc = SourceLocation::Current())
0158 : BasicCrossThreadPersistent(member.Get(), loc) {}
0159
0160 BasicCrossThreadPersistent(
0161 const BasicCrossThreadPersistent& other,
0162 const SourceLocation& loc = SourceLocation::Current())
0163 : BasicCrossThreadPersistent(loc) {
0164
0165 *this = other;
0166 }
0167
0168
0169 template <typename U, typename OtherWeaknessPolicy,
0170 typename OtherLocationPolicy, typename OtherCheckingPolicy,
0171 typename = std::enable_if_t<std::is_base_of<T, U>::value>>
0172 BasicCrossThreadPersistent(
0173 const BasicCrossThreadPersistent<U, OtherWeaknessPolicy,
0174 OtherLocationPolicy,
0175 OtherCheckingPolicy>& other,
0176 const SourceLocation& loc = SourceLocation::Current())
0177 : BasicCrossThreadPersistent(loc) {
0178 *this = other;
0179 }
0180
0181 BasicCrossThreadPersistent(
0182 BasicCrossThreadPersistent&& other,
0183 const SourceLocation& loc = SourceLocation::Current()) noexcept {
0184
0185 *this = std::move(other);
0186 }
0187
0188 BasicCrossThreadPersistent& operator=(
0189 const BasicCrossThreadPersistent& other) {
0190 PersistentRegionLock guard;
0191 AssignSafe(guard, other.Get());
0192 return *this;
0193 }
0194
0195 template <typename U, typename OtherWeaknessPolicy,
0196 typename OtherLocationPolicy, typename OtherCheckingPolicy,
0197 typename = std::enable_if_t<std::is_base_of<T, U>::value>>
0198 BasicCrossThreadPersistent& operator=(
0199 const BasicCrossThreadPersistent<U, OtherWeaknessPolicy,
0200 OtherLocationPolicy,
0201 OtherCheckingPolicy>& other) {
0202 PersistentRegionLock guard;
0203 AssignSafe(guard, other.Get());
0204 return *this;
0205 }
0206
0207 BasicCrossThreadPersistent& operator=(BasicCrossThreadPersistent&& other) {
0208 if (this == &other) return *this;
0209 Clear();
0210 PersistentRegionLock guard;
0211 PersistentBase::operator=(std::move(other));
0212 LocationPolicy::operator=(std::move(other));
0213 if (!IsValid(GetValue())) return *this;
0214 GetNode()->UpdateOwner(this);
0215 other.SetValue(nullptr);
0216 other.SetNode(nullptr);
0217 this->CheckPointer(Get());
0218 return *this;
0219 }
0220
0221
0222
0223
0224
0225
0226 BasicCrossThreadPersistent& operator=(T* other) {
0227 AssignUnsafe(other);
0228 return *this;
0229 }
0230
0231
0232 template <typename U, typename MemberBarrierPolicy,
0233 typename MemberWeaknessTag, typename MemberCheckingPolicy,
0234 typename MemberStorageType,
0235 typename = std::enable_if_t<std::is_base_of<T, U>::value>>
0236 BasicCrossThreadPersistent& operator=(
0237 internal::BasicMember<U, MemberBarrierPolicy, MemberWeaknessTag,
0238 MemberCheckingPolicy, MemberStorageType>
0239 member) {
0240 return operator=(member.Get());
0241 }
0242
0243
0244
0245
0246
0247
0248 BasicCrossThreadPersistent& operator=(std::nullptr_t) {
0249 Clear();
0250 return *this;
0251 }
0252
0253
0254
0255
0256
0257
0258 BasicCrossThreadPersistent& operator=(SentinelPointer s) {
0259 PersistentRegionLock guard;
0260 AssignSafe(guard, s);
0261 return *this;
0262 }
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274 V8_CLANG_NO_SANITIZE("cfi-unrelated-cast") T* Get() const {
0275 return static_cast<T*>(const_cast<void*>(GetValue()));
0276 }
0277
0278
0279
0280
0281 void Clear() {
0282 PersistentRegionLock guard;
0283 AssignSafe(guard, nullptr);
0284 }
0285
0286
0287
0288
0289
0290
0291
0292
0293 T* Release() {
0294 T* result = Get();
0295 Clear();
0296 return result;
0297 }
0298
0299
0300
0301
0302
0303
0304
0305
0306 explicit operator bool() const { return Get(); }
0307
0308
0309
0310
0311
0312
0313
0314
0315 operator T*() const { return Get(); }
0316
0317
0318
0319
0320
0321
0322 T* operator->() const { return Get(); }
0323 T& operator*() const { return *Get(); }
0324
0325 template <typename U, typename OtherWeaknessPolicy = WeaknessPolicy,
0326 typename OtherLocationPolicy = LocationPolicy,
0327 typename OtherCheckingPolicy = CheckingPolicy>
0328 BasicCrossThreadPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
0329 OtherCheckingPolicy>
0330 To() const {
0331 using OtherBasicCrossThreadPersistent =
0332 BasicCrossThreadPersistent<U, OtherWeaknessPolicy, OtherLocationPolicy,
0333 OtherCheckingPolicy>;
0334 PersistentRegionLock guard;
0335 return OtherBasicCrossThreadPersistent(
0336 typename OtherBasicCrossThreadPersistent::UnsafeCtorTag(),
0337 static_cast<U*>(Get()));
0338 }
0339
0340 template <typename U = T,
0341 typename = typename std::enable_if<!BasicCrossThreadPersistent<
0342 U, WeaknessPolicy>::IsStrongPersistent::value>::type>
0343 BasicCrossThreadPersistent<U, internal::StrongCrossThreadPersistentPolicy>
0344 Lock() const {
0345 return BasicCrossThreadPersistent<
0346 U, internal::StrongCrossThreadPersistentPolicy>(*this);
0347 }
0348
0349 private:
0350 static bool IsValid(const void* ptr) {
0351 return ptr && ptr != kSentinelPointer;
0352 }
0353
0354 static void TraceAsRoot(RootVisitor& root_visitor, const void* ptr) {
0355 root_visitor.Trace(*static_cast<const BasicCrossThreadPersistent*>(ptr));
0356 }
0357
0358 void AssignUnsafe(T* ptr) {
0359 const void* old_value = GetValue();
0360 if (IsValid(old_value)) {
0361 PersistentRegionLock guard;
0362 old_value = GetValue();
0363
0364
0365 if (IsValid(old_value)) {
0366 CrossThreadPersistentRegion& region =
0367 this->GetPersistentRegion(old_value);
0368 if (IsValid(ptr) && (®ion == &this->GetPersistentRegion(ptr))) {
0369 SetValue(ptr);
0370 this->CheckPointer(ptr);
0371 return;
0372 }
0373 region.FreeNode(GetNode());
0374 SetNode(nullptr);
0375 } else {
0376 CPPGC_DCHECK(!GetNode());
0377 }
0378 }
0379 SetValue(ptr);
0380 if (!IsValid(ptr)) return;
0381 PersistentRegionLock guard;
0382 SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &TraceAsRoot));
0383 this->CheckPointer(ptr);
0384 }
0385
0386 void AssignSafe(PersistentRegionLock&, T* ptr) {
0387 PersistentRegionLock::AssertLocked();
0388 const void* old_value = GetValue();
0389 if (IsValid(old_value)) {
0390 CrossThreadPersistentRegion& region =
0391 this->GetPersistentRegion(old_value);
0392 if (IsValid(ptr) && (®ion == &this->GetPersistentRegion(ptr))) {
0393 SetValue(ptr);
0394 this->CheckPointer(ptr);
0395 return;
0396 }
0397 region.FreeNode(GetNode());
0398 SetNode(nullptr);
0399 }
0400 SetValue(ptr);
0401 if (!IsValid(ptr)) return;
0402 SetNode(this->GetPersistentRegion(ptr).AllocateNode(this, &TraceAsRoot));
0403 this->CheckPointer(ptr);
0404 }
0405
0406 void ClearFromGC() const {
0407 if (IsValid(GetValueFromGC())) {
0408 WeaknessPolicy::GetPersistentRegion(GetValueFromGC())
0409 .FreeNode(GetNodeFromGC());
0410 CrossThreadPersistentBase::ClearFromGC();
0411 }
0412 }
0413
0414
0415 V8_CLANG_NO_SANITIZE("cfi-unrelated-cast")
0416 T* GetFromGC() const {
0417 return static_cast<T*>(const_cast<void*>(GetValueFromGC()));
0418 }
0419
0420 friend class internal::RootVisitor;
0421 };
0422
0423 template <typename T, typename LocationPolicy, typename CheckingPolicy>
0424 struct IsWeak<
0425 BasicCrossThreadPersistent<T, internal::WeakCrossThreadPersistentPolicy,
0426 LocationPolicy, CheckingPolicy>>
0427 : std::true_type {};
0428
0429 }
0430
0431 namespace subtle {
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444 template <typename T>
0445 using CrossThreadPersistent = internal::BasicCrossThreadPersistent<
0446 T, internal::StrongCrossThreadPersistentPolicy>;
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459 template <typename T>
0460 using WeakCrossThreadPersistent = internal::BasicCrossThreadPersistent<
0461 T, internal::WeakCrossThreadPersistentPolicy>;
0462
0463 }
0464 }
0465
0466 #endif