File indexing completed on 2025-02-22 10:42:27
0001
0002
0003
0004
0005 #ifndef INCLUDE_CPPGC_VISITOR_H_
0006 #define INCLUDE_CPPGC_VISITOR_H_
0007
0008 #include <type_traits>
0009
0010 #include "cppgc/custom-space.h"
0011 #include "cppgc/ephemeron-pair.h"
0012 #include "cppgc/garbage-collected.h"
0013 #include "cppgc/internal/logging.h"
0014 #include "cppgc/internal/member-storage.h"
0015 #include "cppgc/internal/pointer-policies.h"
0016 #include "cppgc/liveness-broker.h"
0017 #include "cppgc/member.h"
0018 #include "cppgc/sentinel-pointer.h"
0019 #include "cppgc/source-location.h"
0020 #include "cppgc/trace-trait.h"
0021 #include "cppgc/type-traits.h"
0022
0023 namespace cppgc {
0024
0025 namespace internal {
0026 template <typename T, typename WeaknessPolicy, typename LocationPolicy,
0027 typename CheckingPolicy>
0028 class BasicCrossThreadPersistent;
0029 template <typename T, typename WeaknessPolicy, typename LocationPolicy,
0030 typename CheckingPolicy>
0031 class BasicPersistent;
0032 class ConservativeTracingVisitor;
0033 class VisitorBase;
0034 class VisitorFactory;
0035 }
0036
0037 using WeakCallback = void (*)(const LivenessBroker&, const void*);
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056 class V8_EXPORT Visitor {
0057 public:
0058 class Key {
0059 private:
0060 Key() = default;
0061 friend class internal::VisitorFactory;
0062 };
0063
0064 explicit Visitor(Key) {}
0065
0066 virtual ~Visitor() = default;
0067
0068
0069
0070
0071
0072
0073 template <typename T>
0074 void Trace(const Member<T>& member) {
0075 const T* value = member.GetRawAtomic();
0076 CPPGC_DCHECK(value != kSentinelPointer);
0077 TraceImpl(value);
0078 }
0079
0080
0081
0082
0083
0084
0085 template <typename T>
0086 void Trace(const WeakMember<T>& weak_member) {
0087 static_assert(sizeof(T), "Pointee type must be fully defined.");
0088 static_assert(internal::IsGarbageCollectedOrMixinType<T>::value,
0089 "T must be GarbageCollected or GarbageCollectedMixin type");
0090 static_assert(!internal::IsAllocatedOnCompactableSpace<T>::value,
0091 "Weak references to compactable objects are not allowed");
0092
0093 const T* value = weak_member.GetRawAtomic();
0094
0095
0096 if (!value) {
0097 return;
0098 }
0099
0100 CPPGC_DCHECK(value != kSentinelPointer);
0101 VisitWeak(value, TraceTrait<T>::GetTraceDescriptor(value),
0102 &HandleWeak<WeakMember<T>>, &weak_member);
0103 }
0104
0105 #if defined(CPPGC_POINTER_COMPRESSION)
0106
0107
0108
0109
0110
0111 template <typename T>
0112 void Trace(const subtle::UncompressedMember<T>& member) {
0113 const T* value = member.GetRawAtomic();
0114 CPPGC_DCHECK(value != kSentinelPointer);
0115 TraceImpl(value);
0116 }
0117 #endif
0118
0119 template <typename T>
0120 void TraceMultiple(const subtle::UncompressedMember<T>* start, size_t len) {
0121 static_assert(sizeof(T), "Pointee type must be fully defined.");
0122 static_assert(internal::IsGarbageCollectedOrMixinType<T>::value,
0123 "T must be GarbageCollected or GarbageCollectedMixin type");
0124 VisitMultipleUncompressedMember(start, len,
0125 &TraceTrait<T>::GetTraceDescriptor);
0126 }
0127
0128 template <typename T,
0129 std::enable_if_t<!std::is_same_v<
0130 Member<T>, subtle::UncompressedMember<T>>>* = nullptr>
0131 void TraceMultiple(const Member<T>* start, size_t len) {
0132 static_assert(sizeof(T), "Pointee type must be fully defined.");
0133 static_assert(internal::IsGarbageCollectedOrMixinType<T>::value,
0134 "T must be GarbageCollected or GarbageCollectedMixin type");
0135 #if defined(CPPGC_POINTER_COMPRESSION)
0136 static_assert(std::is_same_v<Member<T>, subtle::CompressedMember<T>>,
0137 "Member and CompressedMember must be the same.");
0138 VisitMultipleCompressedMember(start, len,
0139 &TraceTrait<T>::GetTraceDescriptor);
0140 #endif
0141 }
0142
0143
0144
0145
0146
0147
0148
0149 template <typename T>
0150 void Trace(const T& object) {
0151 #if V8_ENABLE_CHECKS
0152
0153
0154
0155
0156 CheckObjectNotInConstruction(&object);
0157 #endif
0158 TraceTrait<T>::Trace(this, &object);
0159 }
0160
0161 template <typename T>
0162 void TraceMultiple(const T* start, size_t len) {
0163 #if V8_ENABLE_CHECKS
0164
0165
0166
0167
0168 CheckObjectNotInConstruction(start);
0169 #endif
0170 for (size_t i = 0; i < len; ++i) {
0171 const T* object = &start[i];
0172 if constexpr (std::is_polymorphic_v<T>) {
0173
0174
0175 if (*reinterpret_cast<const uintptr_t*>(object) == 0) continue;
0176 }
0177 TraceTrait<T>::Trace(this, object);
0178 }
0179 }
0180
0181
0182
0183
0184
0185
0186
0187 template <typename T, void (T::*method)(const LivenessBroker&)>
0188 void RegisterWeakCallbackMethod(const T* object) {
0189 RegisterWeakCallback(&WeakCallbackMethodDelegate<T, method>, object);
0190 }
0191
0192
0193
0194
0195
0196
0197
0198 template <typename K, typename V>
0199 void Trace(const EphemeronPair<K, V>& ephemeron_pair) {
0200 TraceEphemeron(ephemeron_pair.key, &ephemeron_pair.value);
0201 RegisterWeakCallbackMethod<EphemeronPair<K, V>,
0202 &EphemeronPair<K, V>::ClearValueIfKeyIsDead>(
0203 &ephemeron_pair);
0204 }
0205
0206
0207
0208
0209
0210
0211
0212
0213 template <typename KeyType, typename ValueType>
0214 void TraceEphemeron(const WeakMember<KeyType>& weak_member_key,
0215 const Member<ValueType>* member_value) {
0216 const KeyType* key = weak_member_key.GetRawAtomic();
0217 if (!key) return;
0218
0219
0220 CPPGC_DCHECK(member_value);
0221 const ValueType* value = member_value->GetRawAtomic();
0222 if (!value) return;
0223
0224
0225 TraceDescriptor value_desc =
0226 TraceTrait<ValueType>::GetTraceDescriptor(value);
0227 CPPGC_DCHECK(value_desc.base_object_payload);
0228 const void* key_base_object_payload =
0229 TraceTrait<KeyType>::GetTraceDescriptor(key).base_object_payload;
0230 CPPGC_DCHECK(key_base_object_payload);
0231
0232 VisitEphemeron(key_base_object_payload, value, value_desc);
0233 }
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246 template <typename KeyType, typename ValueType>
0247 void TraceEphemeron(const WeakMember<KeyType>& weak_member_key,
0248 const ValueType* value) {
0249 static_assert(!IsGarbageCollectedOrMixinTypeV<ValueType>,
0250 "garbage-collected types must use WeakMember and Member");
0251 const KeyType* key = weak_member_key.GetRawAtomic();
0252 if (!key) return;
0253
0254
0255 CPPGC_DCHECK(value);
0256 TraceDescriptor value_desc =
0257 TraceTrait<ValueType>::GetTraceDescriptor(value);
0258
0259
0260 CPPGC_DCHECK(!value_desc.base_object_payload);
0261
0262
0263 const void* key_base_object_payload =
0264 TraceTrait<KeyType>::GetTraceDescriptor(key).base_object_payload;
0265 CPPGC_DCHECK(key_base_object_payload);
0266
0267 VisitEphemeron(key_base_object_payload, value, value_desc);
0268 }
0269
0270
0271
0272
0273
0274
0275 template <typename T>
0276 void TraceStrongly(const WeakMember<T>& weak_member) {
0277 const T* value = weak_member.GetRawAtomic();
0278 CPPGC_DCHECK(value != kSentinelPointer);
0279 TraceImpl(value);
0280 }
0281
0282
0283
0284
0285
0286
0287 template <typename T>
0288 void TraceStrongContainer(const T* object) {
0289 TraceImpl(object);
0290 }
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300 template <typename T>
0301 void TraceWeakContainer(const T* object, WeakCallback callback,
0302 const void* callback_data) {
0303 if (!object) return;
0304 VisitWeakContainer(object, TraceTrait<T>::GetTraceDescriptor(object),
0305 TraceTrait<T>::GetWeakTraceDescriptor(object), callback,
0306 callback_data);
0307 }
0308
0309
0310
0311
0312
0313
0314
0315
0316 template <typename T>
0317 void RegisterMovableReference(const T** slot) {
0318 static_assert(internal::IsAllocatedOnCompactableSpace<T>::value,
0319 "Only references to objects allocated on compactable spaces "
0320 "should be registered as movable slots.");
0321 static_assert(!IsGarbageCollectedMixinTypeV<T>,
0322 "Mixin types do not support compaction.");
0323 HandleMovableReference(reinterpret_cast<const void**>(slot));
0324 }
0325
0326
0327
0328
0329
0330
0331
0332 virtual void RegisterWeakCallback(WeakCallback callback, const void* data) {}
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347 virtual V8_WARN_UNUSED_RESULT bool DeferTraceToMutatorThreadIfConcurrent(
0348 const void* parameter, TraceCallback callback, size_t deferred_size) {
0349
0350 return false;
0351 }
0352
0353 protected:
0354 virtual void Visit(const void* self, TraceDescriptor) {}
0355 virtual void VisitWeak(const void* self, TraceDescriptor, WeakCallback,
0356 const void* weak_member) {}
0357 virtual void VisitEphemeron(const void* key, const void* value,
0358 TraceDescriptor value_desc) {}
0359 virtual void VisitWeakContainer(const void* self, TraceDescriptor strong_desc,
0360 TraceDescriptor weak_desc,
0361 WeakCallback callback, const void* data) {}
0362 virtual void HandleMovableReference(const void**) {}
0363
0364 virtual void VisitMultipleUncompressedMember(
0365 const void* start, size_t len,
0366 TraceDescriptorCallback get_trace_descriptor) {
0367
0368 const char* it = static_cast<const char*>(start);
0369 const char* end = it + len * internal::kSizeOfUncompressedMember;
0370 for (; it < end; it += internal::kSizeOfUncompressedMember) {
0371 const auto* current = reinterpret_cast<const internal::RawPointer*>(it);
0372 const void* object = current->LoadAtomic();
0373 if (!object) continue;
0374
0375 Visit(object, get_trace_descriptor(object));
0376 }
0377 }
0378
0379 #if defined(CPPGC_POINTER_COMPRESSION)
0380 virtual void VisitMultipleCompressedMember(
0381 const void* start, size_t len,
0382 TraceDescriptorCallback get_trace_descriptor) {
0383
0384 const char* it = static_cast<const char*>(start);
0385 const char* end = it + len * internal::kSizeofCompressedMember;
0386 for (; it < end; it += internal::kSizeofCompressedMember) {
0387 const auto* current =
0388 reinterpret_cast<const internal::CompressedPointer*>(it);
0389 const void* object = current->LoadAtomic();
0390 if (!object) continue;
0391
0392 Visit(object, get_trace_descriptor(object));
0393 }
0394 }
0395 #endif
0396
0397 private:
0398 template <typename T, void (T::*method)(const LivenessBroker&)>
0399 static void WeakCallbackMethodDelegate(const LivenessBroker& info,
0400 const void* self) {
0401
0402
0403 (const_cast<T*>(static_cast<const T*>(self))->*method)(info);
0404 }
0405
0406 template <typename PointerType>
0407 static void HandleWeak(const LivenessBroker& info, const void* object) {
0408 const PointerType* weak = static_cast<const PointerType*>(object);
0409 if (!info.IsHeapObjectAlive(weak->GetFromGC())) {
0410 weak->ClearFromGC();
0411 }
0412 }
0413
0414 template <typename T>
0415 void TraceImpl(const T* t) {
0416 static_assert(sizeof(T), "Pointee type must be fully defined.");
0417 static_assert(internal::IsGarbageCollectedOrMixinType<T>::value,
0418 "T must be GarbageCollected or GarbageCollectedMixin type");
0419 if (!t) {
0420 return;
0421 }
0422 Visit(t, TraceTrait<T>::GetTraceDescriptor(t));
0423 }
0424
0425 #if V8_ENABLE_CHECKS
0426 void CheckObjectNotInConstruction(const void* address);
0427 #endif
0428
0429 template <typename T, typename WeaknessPolicy, typename LocationPolicy,
0430 typename CheckingPolicy>
0431 friend class internal::BasicCrossThreadPersistent;
0432 template <typename T, typename WeaknessPolicy, typename LocationPolicy,
0433 typename CheckingPolicy>
0434 friend class internal::BasicPersistent;
0435 friend class internal::ConservativeTracingVisitor;
0436 friend class internal::VisitorBase;
0437 };
0438
0439 namespace internal {
0440
0441 class V8_EXPORT RootVisitor {
0442 public:
0443 explicit RootVisitor(Visitor::Key) {}
0444
0445 virtual ~RootVisitor() = default;
0446
0447 template <typename AnyStrongPersistentType,
0448 std::enable_if_t<
0449 AnyStrongPersistentType::IsStrongPersistent::value>* = nullptr>
0450 void Trace(const AnyStrongPersistentType& p) {
0451 using PointeeType = typename AnyStrongPersistentType::PointeeType;
0452 const void* object = Extract(p);
0453 if (!object) {
0454 return;
0455 }
0456 VisitRoot(object, TraceTrait<PointeeType>::GetTraceDescriptor(object),
0457 p.Location());
0458 }
0459
0460 template <typename AnyWeakPersistentType,
0461 std::enable_if_t<
0462 !AnyWeakPersistentType::IsStrongPersistent::value>* = nullptr>
0463 void Trace(const AnyWeakPersistentType& p) {
0464 using PointeeType = typename AnyWeakPersistentType::PointeeType;
0465 static_assert(!internal::IsAllocatedOnCompactableSpace<PointeeType>::value,
0466 "Weak references to compactable objects are not allowed");
0467 const void* object = Extract(p);
0468 if (!object) {
0469 return;
0470 }
0471 VisitWeakRoot(object, TraceTrait<PointeeType>::GetTraceDescriptor(object),
0472 &HandleWeak<AnyWeakPersistentType>, &p, p.Location());
0473 }
0474
0475 protected:
0476 virtual void VisitRoot(const void*, TraceDescriptor, const SourceLocation&) {}
0477 virtual void VisitWeakRoot(const void* self, TraceDescriptor, WeakCallback,
0478 const void* weak_root, const SourceLocation&) {}
0479
0480 private:
0481 template <typename AnyPersistentType>
0482 static const void* Extract(AnyPersistentType& p) {
0483 using PointeeType = typename AnyPersistentType::PointeeType;
0484 static_assert(sizeof(PointeeType),
0485 "Persistent's pointee type must be fully defined");
0486 static_assert(internal::IsGarbageCollectedOrMixinType<PointeeType>::value,
0487 "Persistent's pointee type must be GarbageCollected or "
0488 "GarbageCollectedMixin");
0489 return p.GetFromGC();
0490 }
0491
0492 template <typename PointerType>
0493 static void HandleWeak(const LivenessBroker& info, const void* object) {
0494 const PointerType* weak = static_cast<const PointerType*>(object);
0495 if (!info.IsHeapObjectAlive(weak->GetFromGC())) {
0496 weak->ClearFromGC();
0497 }
0498 }
0499 };
0500
0501 }
0502 }
0503
0504 #endif