Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-22 10:42:27

0001 // Copyright 2020 the V8 project authors. All rights reserved.
0002 // Use of this source code is governed by a BSD-style license that can be
0003 // found in the LICENSE file.
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 }  // namespace internal
0036 
0037 using WeakCallback = void (*)(const LivenessBroker&, const void*);
0038 
0039 /**
0040  * Visitor passed to trace methods. All managed pointers must have called the
0041  * Visitor's trace method on them.
0042  *
0043  * \code
0044  * class Foo final : public GarbageCollected<Foo> {
0045  *  public:
0046  *   void Trace(Visitor* visitor) const {
0047  *     visitor->Trace(foo_);
0048  *     visitor->Trace(weak_foo_);
0049  *   }
0050  *  private:
0051  *   Member<Foo> foo_;
0052  *   WeakMember<Foo> weak_foo_;
0053  * };
0054  * \endcode
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    * Trace method for Member.
0070    *
0071    * \param member Member reference retaining an object.
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    * Trace method for WeakMember.
0082    *
0083    * \param weak_member WeakMember reference weakly retaining an object.
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     // Bailout assumes that WeakMember emits write barrier.
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    * Trace method for UncompressedMember.
0108    *
0109    * \param member UncompressedMember reference retaining an object.
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  // defined(CPPGC_POINTER_COMPRESSION)
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  // defined(CPPGC_POINTER_COMPRESSION)
0141   }
0142 
0143   /**
0144    * Trace method for inlined objects that are not allocated themselves but
0145    * otherwise follow managed heap layout and have a Trace() method.
0146    *
0147    * \param object reference of the inlined object.
0148    */
0149   template <typename T>
0150   void Trace(const T& object) {
0151 #if V8_ENABLE_CHECKS
0152     // This object is embedded in potentially multiple nested objects. The
0153     // outermost object must not be in construction as such objects are (a) not
0154     // processed immediately, and (b) only processed conservatively if not
0155     // otherwise possible.
0156     CheckObjectNotInConstruction(&object);
0157 #endif  // V8_ENABLE_CHECKS
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     // This object is embedded in potentially multiple nested objects. The
0165     // outermost object must not be in construction as such objects are (a) not
0166     // processed immediately, and (b) only processed conservatively if not
0167     // otherwise possible.
0168     CheckObjectNotInConstruction(start);
0169 #endif  // V8_ENABLE_CHECKS
0170     for (size_t i = 0; i < len; ++i) {
0171       const T* object = &start[i];
0172       if constexpr (std::is_polymorphic_v<T>) {
0173         // The object's vtable may be uninitialized in which case the object is
0174         // not traced.
0175         if (*reinterpret_cast<const uintptr_t*>(object) == 0) continue;
0176       }
0177       TraceTrait<T>::Trace(this, object);
0178     }
0179   }
0180 
0181   /**
0182    * Registers a weak callback method on the object of type T. See
0183    * LivenessBroker for an usage example.
0184    *
0185    * \param object of type T specifying a weak callback method.
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    * Trace method for EphemeronPair.
0194    *
0195    * \param ephemeron_pair EphemeronPair reference weakly retaining a key object
0196    * and strongly retaining a value object in case the key object is alive.
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    * Trace method for a single ephemeron. Used for tracing a raw ephemeron in
0208    * which the `key` and `value` are kept separately.
0209    *
0210    * \param weak_member_key WeakMember reference weakly retaining a key object.
0211    * \param member_value Member reference with ephemeron semantics.
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     // `value` must always be non-null.
0220     CPPGC_DCHECK(member_value);
0221     const ValueType* value = member_value->GetRawAtomic();
0222     if (!value) return;
0223 
0224     // KeyType and ValueType may refer to GarbageCollectedMixin.
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    * Trace method for a single ephemeron. Used for tracing a raw ephemeron in
0237    * which the `key` and `value` are kept separately. Note that this overload
0238    * is for non-GarbageCollected `value`s that can be traced though.
0239    *
0240    * \param key `WeakMember` reference weakly retaining a key object.
0241    * \param value Reference weakly retaining a value object. Note that
0242    *   `ValueType` here should not be `Member`. It is expected that
0243    *   `TraceTrait<ValueType>::GetTraceDescriptor(value)` returns a
0244    *   `TraceDescriptor` with a null base pointer but a valid trace method.
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     // `value` must always be non-null.
0255     CPPGC_DCHECK(value);
0256     TraceDescriptor value_desc =
0257         TraceTrait<ValueType>::GetTraceDescriptor(value);
0258     // `value_desc.base_object_payload` must be null as this override is only
0259     // taken for non-garbage-collected values.
0260     CPPGC_DCHECK(!value_desc.base_object_payload);
0261 
0262     // KeyType might be a GarbageCollectedMixin.
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    * Trace method that strongifies a WeakMember.
0272    *
0273    * \param weak_member WeakMember reference retaining an object.
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    * Trace method for retaining containers strongly.
0284    *
0285    * \param object reference to the container.
0286    */
0287   template <typename T>
0288   void TraceStrongContainer(const T* object) {
0289     TraceImpl(object);
0290   }
0291 
0292   /**
0293    * Trace method for retaining containers weakly. Note that weak containers
0294    * should emit write barriers.
0295    *
0296    * \param object reference to the container.
0297    * \param callback to be invoked.
0298    * \param callback_data custom data that is passed to the callback.
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    * Registers a slot containing a reference to an object allocated on a
0311    * compactable space. Such references maybe be arbitrarily moved by the GC.
0312    *
0313    * \param slot location of reference to object that might be moved by the GC.
0314    * The slot must contain an uncompressed pointer.
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    * Registers a weak callback that is invoked during garbage collection.
0328    *
0329    * \param callback to be invoked.
0330    * \param data custom data that is passed to the callback.
0331    */
0332   virtual void RegisterWeakCallback(WeakCallback callback, const void* data) {}
0333 
0334   /**
0335    * Defers tracing an object from a concurrent thread to the mutator thread.
0336    * Should be called by Trace methods of types that are not safe to trace
0337    * concurrently.
0338    *
0339    * \param parameter tells the trace callback which object was deferred.
0340    * \param callback to be invoked for tracing on the mutator thread.
0341    * \param deferred_size size of deferred object.
0342    *
0343    * \returns false if the object does not need to be deferred (i.e. currently
0344    * traced on the mutator thread) and true otherwise (i.e. currently traced on
0345    * a concurrent thread).
0346    */
0347   virtual V8_WARN_UNUSED_RESULT bool DeferTraceToMutatorThreadIfConcurrent(
0348       const void* parameter, TraceCallback callback, size_t deferred_size) {
0349     // By default tracing is not deferred.
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     // Default implementation merely delegates to Visit().
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     // Default implementation merely delegates to Visit().
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  // defined(CPPGC_POINTER_COMPRESSION)
0396 
0397  private:
0398   template <typename T, void (T::*method)(const LivenessBroker&)>
0399   static void WeakCallbackMethodDelegate(const LivenessBroker& info,
0400                                          const void* self) {
0401     // Callback is registered through a potential const Trace method but needs
0402     // to be able to modify fields. See HandleWeak.
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  // V8_ENABLE_CHECKS
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 }  // namespace internal
0502 }  // namespace cppgc
0503 
0504 #endif  // INCLUDE_CPPGC_VISITOR_H_