Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-01-10 10:15:07

0001 // Copyright 2021 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_V8_PERSISTENT_HANDLE_H_
0006 #define INCLUDE_V8_PERSISTENT_HANDLE_H_
0007 
0008 #include "v8-internal.h"            // NOLINT(build/include_directory)
0009 #include "v8-local-handle.h"        // NOLINT(build/include_directory)
0010 #include "v8-weak-callback-info.h"  // NOLINT(build/include_directory)
0011 #include "v8config.h"               // NOLINT(build/include_directory)
0012 
0013 namespace v8 {
0014 
0015 class Isolate;
0016 template <class K, class V, class T>
0017 class PersistentValueMapBase;
0018 template <class T>
0019 class Global;
0020 template <class T>
0021 class PersistentBase;
0022 template <class K, class V, class T>
0023 class PersistentValueMap;
0024 class Value;
0025 
0026 namespace api_internal {
0027 V8_EXPORT internal::Address* Eternalize(v8::Isolate* isolate, Value* handle);
0028 V8_EXPORT internal::Address* CopyGlobalReference(internal::Address* from);
0029 V8_EXPORT void DisposeGlobal(internal::Address* global_handle);
0030 V8_EXPORT void MakeWeak(internal::Address** location_addr);
0031 V8_EXPORT void* ClearWeak(internal::Address* location);
0032 V8_EXPORT void AnnotateStrongRetainer(internal::Address* location,
0033                                       const char* label);
0034 V8_EXPORT internal::Address* GlobalizeReference(internal::Isolate* isolate,
0035                                                 internal::Address value);
0036 V8_EXPORT void MoveGlobalReference(internal::Address** from,
0037                                    internal::Address** to);
0038 }  // namespace api_internal
0039 
0040 /**
0041  * Eternal handles are set-once handles that live for the lifetime of the
0042  * isolate.
0043  */
0044 template <class T>
0045 class Eternal : public api_internal::IndirectHandleBase {
0046  public:
0047   V8_INLINE Eternal() = default;
0048 
0049   /**
0050    * Constructor for handling automatic up casting.
0051    */
0052   template <class S>
0053     requires(std::is_base_of_v<T, S>)
0054   V8_INLINE Eternal(Isolate* isolate, Local<S> handle) {
0055     Set(isolate, handle);
0056   }
0057 
0058   // Can only be safely called if already set.
0059   V8_INLINE Local<T> Get(Isolate* isolate) const {
0060     // The eternal handle will never go away, so as with the roots, we don't
0061     // even need to open a handle.
0062     return Local<T>::FromSlot(slot());
0063   }
0064 
0065   template <class S>
0066     requires(std::is_base_of_v<T, S>)
0067   void Set(Isolate* isolate, Local<S> handle) {
0068     slot() =
0069         api_internal::Eternalize(isolate, *handle.template UnsafeAs<Value>());
0070   }
0071 };
0072 
0073 namespace api_internal {
0074 V8_EXPORT void MakeWeak(internal::Address* location, void* data,
0075                         WeakCallbackInfo<void>::Callback weak_callback,
0076                         WeakCallbackType type);
0077 }  // namespace api_internal
0078 
0079 /**
0080  * An object reference that is independent of any handle scope.  Where
0081  * a Local handle only lives as long as the HandleScope in which it was
0082  * allocated, a PersistentBase handle remains valid until it is explicitly
0083  * disposed using Reset().
0084  *
0085  * A persistent handle contains a reference to a storage cell within
0086  * the V8 engine which holds an object value and which is updated by
0087  * the garbage collector whenever the object is moved.  A new storage
0088  * cell can be created using the constructor or PersistentBase::Reset and
0089  * existing handles can be disposed using PersistentBase::Reset.
0090  *
0091  */
0092 template <class T>
0093 class PersistentBase : public api_internal::IndirectHandleBase {
0094  public:
0095   /**
0096    * If non-empty, destroy the underlying storage cell
0097    * IsEmpty() will return true after this call.
0098    */
0099   V8_INLINE void Reset();
0100 
0101   /**
0102    * If non-empty, destroy the underlying storage cell
0103    * and create a new one with the contents of other if other is non empty
0104    */
0105   template <class S>
0106   V8_INLINE void Reset(Isolate* isolate, const Local<S>& other);
0107 
0108   /**
0109    * If non-empty, destroy the underlying storage cell
0110    * and create a new one with the contents of other if other is non empty
0111    */
0112   template <class S>
0113   V8_INLINE void Reset(Isolate* isolate, const PersistentBase<S>& other);
0114 
0115   V8_INLINE Local<T> Get(Isolate* isolate) const {
0116     return Local<T>::New(isolate, *this);
0117   }
0118 
0119   template <class S>
0120   V8_INLINE bool operator==(const PersistentBase<S>& that) const {
0121     return internal::HandleHelper::EqualHandles(*this, that);
0122   }
0123 
0124   template <class S>
0125   V8_INLINE bool operator==(const Local<S>& that) const {
0126     return internal::HandleHelper::EqualHandles(*this, that);
0127   }
0128 
0129   template <class S>
0130   V8_INLINE bool operator!=(const PersistentBase<S>& that) const {
0131     return !operator==(that);
0132   }
0133 
0134   template <class S>
0135   V8_INLINE bool operator!=(const Local<S>& that) const {
0136     return !operator==(that);
0137   }
0138 
0139   /**
0140    * Install a finalization callback on this object.
0141    * NOTE: There is no guarantee as to *when* or even *if* the callback is
0142    * invoked. The invocation is performed solely on a best effort basis.
0143    * As always, GC-based finalization should *not* be relied upon for any
0144    * critical form of resource management!
0145    *
0146    * The callback is supposed to reset the handle. No further V8 API may be
0147    * called in this callback. In case additional work involving V8 needs to be
0148    * done, a second callback can be scheduled using
0149    * WeakCallbackInfo<void>::SetSecondPassCallback.
0150    */
0151   template <typename P>
0152   V8_INLINE void SetWeak(P* parameter,
0153                          typename WeakCallbackInfo<P>::Callback callback,
0154                          WeakCallbackType type);
0155 
0156   /**
0157    * Turns this handle into a weak phantom handle without finalization callback.
0158    * The handle will be reset automatically when the garbage collector detects
0159    * that the object is no longer reachable.
0160    */
0161   V8_INLINE void SetWeak();
0162 
0163   template <typename P>
0164   V8_INLINE P* ClearWeak();
0165 
0166   // TODO(dcarney): remove this.
0167   V8_INLINE void ClearWeak() { ClearWeak<void>(); }
0168 
0169   /**
0170    * Annotates the strong handle with the given label, which is then used by the
0171    * heap snapshot generator as a name of the edge from the root to the handle.
0172    * The function does not take ownership of the label and assumes that the
0173    * label is valid as long as the handle is valid.
0174    */
0175   V8_INLINE void AnnotateStrongRetainer(const char* label);
0176 
0177   /** Returns true if the handle's reference is weak.  */
0178   V8_INLINE bool IsWeak() const;
0179 
0180   /**
0181    * Assigns a wrapper class ID to the handle.
0182    */
0183   V8_INLINE void SetWrapperClassId(uint16_t class_id);
0184 
0185   /**
0186    * Returns the class ID previously assigned to this handle or 0 if no class ID
0187    * was previously assigned.
0188    */
0189   V8_INLINE uint16_t WrapperClassId() const;
0190 
0191   PersistentBase(const PersistentBase& other) = delete;
0192   void operator=(const PersistentBase&) = delete;
0193 
0194  private:
0195   friend class Isolate;
0196   friend class Utils;
0197   template <class F>
0198   friend class Local;
0199   template <class F1, class F2>
0200   friend class Persistent;
0201   template <class F>
0202   friend class Global;
0203   template <class F>
0204   friend class PersistentBase;
0205   template <class F>
0206   friend class ReturnValue;
0207   template <class F1, class F2, class F3>
0208   friend class PersistentValueMapBase;
0209   friend class Object;
0210   friend class internal::ValueHelper;
0211 
0212   V8_INLINE PersistentBase() = default;
0213 
0214   V8_INLINE explicit PersistentBase(internal::Address* location)
0215       : IndirectHandleBase(location) {}
0216 
0217   V8_INLINE static internal::Address* New(Isolate* isolate, T* that);
0218 };
0219 
0220 /**
0221  * Default traits for Persistent. This class does not allow
0222  * use of the copy constructor or assignment operator.
0223  * At present kResetInDestructor is not set, but that will change in a future
0224  * version.
0225  */
0226 template <class T>
0227 class NonCopyablePersistentTraits {
0228  public:
0229   using NonCopyablePersistent = Persistent<T, NonCopyablePersistentTraits<T>>;
0230   static const bool kResetInDestructor = false;
0231   template <class S, class M>
0232   V8_INLINE static void Copy(const Persistent<S, M>& source,
0233                              NonCopyablePersistent* dest) {
0234     static_assert(sizeof(S) < 0,
0235                   "NonCopyablePersistentTraits::Copy is not instantiable");
0236   }
0237 };
0238 
0239 /**
0240  * A PersistentBase which allows copy and assignment.
0241  *
0242  * Copy, assignment and destructor behavior is controlled by the traits
0243  * class M.
0244  *
0245  * CAVEAT: Persistent objects do not have proper destruction behavior by default
0246  * and as such will leak the object without explicit clear. Consider using
0247  * `v8::Global` instead which has proper destruction and move semantics.
0248  */
0249 template <class T, class M>
0250 class Persistent : public PersistentBase<T> {
0251  public:
0252   /**
0253    * A Persistent with no storage cell.
0254    */
0255   V8_INLINE Persistent() = default;
0256 
0257   /**
0258    * Construct a Persistent from a Local with automatic up casting.
0259    * When the Local is non-empty, a new storage cell is created
0260    * pointing to the same object, and no flags are set.
0261    */
0262   template <class S>
0263     requires(std::is_base_of_v<T, S>)
0264   V8_INLINE Persistent(Isolate* isolate, Local<S> that)
0265       : PersistentBase<T>(
0266             PersistentBase<T>::New(isolate, that.template value<S>())) {}
0267 
0268   /**
0269    * Construct a Persistent from a Persistent with automatic up casting.
0270    * When the Persistent is non-empty, a new storage cell is created
0271    * pointing to the same object, and no flags are set.
0272    */
0273   template <class S, class M2>
0274     requires(std::is_base_of_v<T, S>)
0275   V8_INLINE Persistent(Isolate* isolate, const Persistent<S, M2>& that)
0276       : PersistentBase<T>(
0277             PersistentBase<T>::New(isolate, that.template value<S>())) {}
0278 
0279   /**
0280    * The copy constructors and assignment operator create a Persistent
0281    * exactly as the Persistent constructor, but the Copy function from the
0282    * traits class is called, allowing the setting of flags based on the
0283    * copied Persistent.
0284    */
0285   V8_INLINE Persistent(const Persistent& that) : PersistentBase<T>() {
0286     Copy(that);
0287   }
0288   template <class S, class M2>
0289   V8_INLINE Persistent(const Persistent<S, M2>& that) : PersistentBase<T>() {
0290     Copy(that);
0291   }
0292   V8_INLINE Persistent& operator=(const Persistent& that) {
0293     Copy(that);
0294     return *this;
0295   }
0296   template <class S, class M2>
0297   V8_INLINE Persistent& operator=(const Persistent<S, M2>& that) {
0298     Copy(that);
0299     return *this;
0300   }
0301 
0302   /**
0303    * The destructor will dispose the Persistent based on the
0304    * kResetInDestructor flags in the traits class.  Since not calling dispose
0305    * can result in a memory leak, it is recommended to always set this flag.
0306    */
0307   V8_INLINE ~Persistent() {
0308     if (M::kResetInDestructor) this->Reset();
0309   }
0310 
0311   // TODO(dcarney): this is pretty useless, fix or remove
0312   template <class S, class M2>
0313   V8_INLINE static Persistent<T, M>& Cast(const Persistent<S, M2>& that) {
0314 #ifdef V8_ENABLE_CHECKS
0315     // If we're going to perform the type check then we have to check
0316     // that the handle isn't empty before doing the checked cast.
0317     if (!that.IsEmpty()) T::Cast(that.template value<S>());
0318 #endif
0319     return reinterpret_cast<Persistent<T, M>&>(
0320         const_cast<Persistent<S, M2>&>(that));
0321   }
0322 
0323   // TODO(dcarney): this is pretty useless, fix or remove
0324   template <class S, class M2>
0325   V8_INLINE Persistent<S, M2>& As() const {
0326     return Persistent<S, M2>::Cast(*this);
0327   }
0328 
0329  private:
0330   friend class Isolate;
0331   friend class Utils;
0332   template <class F>
0333   friend class Local;
0334   template <class F1, class F2>
0335   friend class Persistent;
0336   template <class F>
0337   friend class ReturnValue;
0338 
0339   template <class S, class M2>
0340   V8_INLINE void Copy(const Persistent<S, M2>& that);
0341 };
0342 
0343 /**
0344  * A PersistentBase which has move semantics.
0345  *
0346  * Note: Persistent class hierarchy is subject to future changes.
0347  */
0348 template <class T>
0349 class Global : public PersistentBase<T> {
0350  public:
0351   /**
0352    * A Global with no storage cell.
0353    */
0354   V8_INLINE Global() = default;
0355 
0356   /**
0357    * Construct a Global from a Local with automatic up casting.
0358    * When the Local is non-empty, a new storage cell is created
0359    * pointing to the same object, and no flags are set.
0360    */
0361   template <class S>
0362     requires(std::is_base_of_v<T, S>)
0363   V8_INLINE Global(Isolate* isolate, Local<S> that)
0364       : PersistentBase<T>(
0365             PersistentBase<T>::New(isolate, that.template value<S>())) {}
0366 
0367   /**
0368    * Construct a Global from a PersistentBase with automatic up casting.
0369    * When the Persistent is non-empty, a new storage cell is created
0370    * pointing to the same object, and no flags are set.
0371    */
0372   template <class S>
0373     requires(std::is_base_of_v<T, S>)
0374   V8_INLINE Global(Isolate* isolate, const PersistentBase<S>& that)
0375       : PersistentBase<T>(
0376             PersistentBase<T>::New(isolate, that.template value<S>())) {}
0377 
0378   /**
0379    * Move constructor.
0380    */
0381   V8_INLINE Global(Global&& other);
0382 
0383   V8_INLINE ~Global() { this->Reset(); }
0384 
0385   /**
0386    * Move via assignment.
0387    */
0388   template <class S>
0389   V8_INLINE Global& operator=(Global<S>&& rhs);
0390 
0391   /**
0392    * Pass allows returning uniques from functions, etc.
0393    */
0394   Global Pass() { return static_cast<Global&&>(*this); }
0395 
0396   /*
0397    * For compatibility with Chromium's base::Bind (base::Passed).
0398    */
0399   using MoveOnlyTypeForCPP03 = void;
0400 
0401   Global(const Global&) = delete;
0402   void operator=(const Global&) = delete;
0403 
0404  private:
0405   template <class F>
0406   friend class ReturnValue;
0407 };
0408 
0409 // UniquePersistent is an alias for Global for historical reason.
0410 template <class T>
0411 using UniquePersistent = Global<T>;
0412 
0413 /**
0414  * Interface for iterating through all the persistent handles in the heap.
0415  */
0416 class V8_EXPORT PersistentHandleVisitor {
0417  public:
0418   virtual ~PersistentHandleVisitor() = default;
0419   virtual void VisitPersistentHandle(Persistent<Value>* value,
0420                                      uint16_t class_id) {}
0421 };
0422 
0423 template <class T>
0424 internal::Address* PersistentBase<T>::New(Isolate* isolate, T* that) {
0425   if (internal::ValueHelper::IsEmpty(that)) return nullptr;
0426   return api_internal::GlobalizeReference(
0427       reinterpret_cast<internal::Isolate*>(isolate),
0428       internal::ValueHelper::ValueAsAddress(that));
0429 }
0430 
0431 template <class T, class M>
0432 template <class S, class M2>
0433 void Persistent<T, M>::Copy(const Persistent<S, M2>& that) {
0434   static_assert(std::is_base_of<T, S>::value, "type check");
0435   this->Reset();
0436   if (that.IsEmpty()) return;
0437   this->slot() = api_internal::CopyGlobalReference(that.slot());
0438   M::Copy(that, this);
0439 }
0440 
0441 template <class T>
0442 bool PersistentBase<T>::IsWeak() const {
0443   using I = internal::Internals;
0444   if (this->IsEmpty()) return false;
0445   return I::GetNodeState(this->slot()) == I::kNodeStateIsWeakValue;
0446 }
0447 
0448 template <class T>
0449 void PersistentBase<T>::Reset() {
0450   if (this->IsEmpty()) return;
0451   api_internal::DisposeGlobal(this->slot());
0452   this->Clear();
0453 }
0454 
0455 /**
0456  * If non-empty, destroy the underlying storage cell
0457  * and create a new one with the contents of other if other is non empty
0458  */
0459 template <class T>
0460 template <class S>
0461 void PersistentBase<T>::Reset(Isolate* isolate, const Local<S>& other) {
0462   static_assert(std::is_base_of<T, S>::value, "type check");
0463   Reset();
0464   if (other.IsEmpty()) return;
0465   this->slot() = New(isolate, *other);
0466 }
0467 
0468 /**
0469  * If non-empty, destroy the underlying storage cell
0470  * and create a new one with the contents of other if other is non empty
0471  */
0472 template <class T>
0473 template <class S>
0474 void PersistentBase<T>::Reset(Isolate* isolate,
0475                               const PersistentBase<S>& other) {
0476   static_assert(std::is_base_of<T, S>::value, "type check");
0477   Reset();
0478   if (other.IsEmpty()) return;
0479   this->slot() = New(isolate, other.template value<S>());
0480 }
0481 
0482 template <class T>
0483 template <typename P>
0484 V8_INLINE void PersistentBase<T>::SetWeak(
0485     P* parameter, typename WeakCallbackInfo<P>::Callback callback,
0486     WeakCallbackType type) {
0487   using Callback = WeakCallbackInfo<void>::Callback;
0488 #if (__GNUC__ >= 8) && !defined(__clang__)
0489 #pragma GCC diagnostic push
0490 #pragma GCC diagnostic ignored "-Wcast-function-type"
0491 #endif
0492   api_internal::MakeWeak(this->slot(), parameter,
0493                          reinterpret_cast<Callback>(callback), type);
0494 #if (__GNUC__ >= 8) && !defined(__clang__)
0495 #pragma GCC diagnostic pop
0496 #endif
0497 }
0498 
0499 template <class T>
0500 void PersistentBase<T>::SetWeak() {
0501   api_internal::MakeWeak(&this->slot());
0502 }
0503 
0504 template <class T>
0505 template <typename P>
0506 P* PersistentBase<T>::ClearWeak() {
0507   return reinterpret_cast<P*>(api_internal::ClearWeak(this->slot()));
0508 }
0509 
0510 template <class T>
0511 void PersistentBase<T>::AnnotateStrongRetainer(const char* label) {
0512   api_internal::AnnotateStrongRetainer(this->slot(), label);
0513 }
0514 
0515 template <class T>
0516 void PersistentBase<T>::SetWrapperClassId(uint16_t class_id) {
0517   using I = internal::Internals;
0518   if (this->IsEmpty()) return;
0519   uint8_t* addr = reinterpret_cast<uint8_t*>(slot()) + I::kNodeClassIdOffset;
0520   *reinterpret_cast<uint16_t*>(addr) = class_id;
0521 }
0522 
0523 template <class T>
0524 uint16_t PersistentBase<T>::WrapperClassId() const {
0525   using I = internal::Internals;
0526   if (this->IsEmpty()) return 0;
0527   uint8_t* addr = reinterpret_cast<uint8_t*>(slot()) + I::kNodeClassIdOffset;
0528   return *reinterpret_cast<uint16_t*>(addr);
0529 }
0530 
0531 template <class T>
0532 Global<T>::Global(Global&& other) : PersistentBase<T>(other.slot()) {
0533   if (!other.IsEmpty()) {
0534     api_internal::MoveGlobalReference(&other.slot(), &this->slot());
0535     other.Clear();
0536   }
0537 }
0538 
0539 template <class T>
0540 template <class S>
0541 Global<T>& Global<T>::operator=(Global<S>&& rhs) {
0542   static_assert(std::is_base_of<T, S>::value, "type check");
0543   if (this != &rhs) {
0544     this->Reset();
0545     if (!rhs.IsEmpty()) {
0546       this->slot() = rhs.slot();
0547       api_internal::MoveGlobalReference(&rhs.slot(), &this->slot());
0548       rhs.Clear();
0549     }
0550   }
0551   return *this;
0552 }
0553 
0554 }  // namespace v8
0555 
0556 #endif  // INCLUDE_V8_PERSISTENT_HANDLE_H_