1// Copyright 2021 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef INCLUDE_V8_PERSISTENT_HANDLE_H_
6#define INCLUDE_V8_PERSISTENT_HANDLE_H_
7
8#include "v8-internal.h"            // NOLINT(build/include_directory)
9#include "v8-local-handle.h"        // NOLINT(build/include_directory)
10#include "v8-weak-callback-info.h"  // NOLINT(build/include_directory)
11#include "v8config.h"               // NOLINT(build/include_directory)
12
13namespace v8 {
14
15class Isolate;
16template <class K, class V, class T>
17class PersistentValueMapBase;
18template <class V, class T>
19class PersistentValueVector;
20template <class T>
21class Global;
22template <class T>
23class PersistentBase;
24template <class K, class V, class T>
25class PersistentValueMap;
26class Value;
27
28namespace api_internal {
29V8_EXPORT Value* Eternalize(v8::Isolate* isolate, Value* handle);
30V8_EXPORT internal::Address* CopyGlobalReference(internal::Address* from);
31V8_EXPORT void DisposeGlobal(internal::Address* global_handle);
32V8_EXPORT void MakeWeak(internal::Address** location_addr);
33V8_EXPORT void* ClearWeak(internal::Address* location);
34V8_EXPORT void AnnotateStrongRetainer(internal::Address* location,
35                                      const char* label);
36V8_EXPORT internal::Address* GlobalizeReference(internal::Isolate* isolate,
37                                                internal::Address* handle);
38V8_EXPORT void MoveGlobalReference(internal::Address** from,
39                                   internal::Address** to);
40}  // namespace api_internal
41
42/**
43 * Eternal handles are set-once handles that live for the lifetime of the
44 * isolate.
45 */
46template <class T>
47class Eternal {
48 public:
49  V8_INLINE Eternal() : val_(nullptr) {}
50  template <class S>
51  V8_INLINE Eternal(Isolate* isolate, Local<S> handle) : val_(nullptr) {
52    Set(isolate, handle);
53  }
54  // Can only be safely called if already set.
55  V8_INLINE Local<T> Get(Isolate* isolate) const {
56    // The eternal handle will never go away, so as with the roots, we don't
57    // even need to open a handle.
58    return Local<T>(val_);
59  }
60
61  V8_INLINE bool IsEmpty() const { return val_ == nullptr; }
62
63  template <class S>
64  void Set(Isolate* isolate, Local<S> handle) {
65    static_assert(std::is_base_of<T, S>::value, "type check");
66    val_ = reinterpret_cast<T*>(
67        api_internal::Eternalize(isolate, reinterpret_cast<Value*>(*handle)));
68  }
69
70 private:
71  T* val_;
72};
73
74namespace api_internal {
75V8_EXPORT void MakeWeak(internal::Address* location, void* data,
76                        WeakCallbackInfo<void>::Callback weak_callback,
77                        WeakCallbackType type);
78}  // namespace api_internal
79
80/**
81 * An object reference that is independent of any handle scope.  Where
82 * a Local handle only lives as long as the HandleScope in which it was
83 * allocated, a PersistentBase handle remains valid until it is explicitly
84 * disposed using Reset().
85 *
86 * A persistent handle contains a reference to a storage cell within
87 * the V8 engine which holds an object value and which is updated by
88 * the garbage collector whenever the object is moved.  A new storage
89 * cell can be created using the constructor or PersistentBase::Reset and
90 * existing handles can be disposed using PersistentBase::Reset.
91 *
92 */
93template <class T>
94class PersistentBase {
95 public:
96  /**
97   * If non-empty, destroy the underlying storage cell
98   * IsEmpty() will return true after this call.
99   */
100  V8_INLINE void Reset();
101
102  /**
103   * If non-empty, destroy the underlying storage cell
104   * and create a new one with the contents of other if other is non empty
105   */
106  template <class S>
107  V8_INLINE void Reset(Isolate* isolate, const Local<S>& other);
108
109  /**
110   * If non-empty, destroy the underlying storage cell
111   * and create a new one with the contents of other if other is non empty
112   */
113  template <class S>
114  V8_INLINE void Reset(Isolate* isolate, const PersistentBase<S>& other);
115
116  V8_INLINE bool IsEmpty() const { return val_ == nullptr; }
117  V8_INLINE void Empty() { val_ = 0; }
118
119  V8_INLINE Local<T> Get(Isolate* isolate) const {
120    return Local<T>::New(isolate, *this);
121  }
122
123  template <class S>
124  V8_INLINE bool operator==(const PersistentBase<S>& that) const {
125    internal::Address* a = reinterpret_cast<internal::Address*>(this->val_);
126    internal::Address* b = reinterpret_cast<internal::Address*>(that.val_);
127    if (a == nullptr) return b == nullptr;
128    if (b == nullptr) return false;
129    return *a == *b;
130  }
131
132  template <class S>
133  V8_INLINE bool operator==(const Local<S>& that) const {
134    internal::Address* a = reinterpret_cast<internal::Address*>(this->val_);
135    internal::Address* b = reinterpret_cast<internal::Address*>(that.val_);
136    if (a == nullptr) return b == nullptr;
137    if (b == nullptr) return false;
138    return *a == *b;
139  }
140
141  template <class S>
142  V8_INLINE bool operator!=(const PersistentBase<S>& that) const {
143    return !operator==(that);
144  }
145
146  template <class S>
147  V8_INLINE bool operator!=(const Local<S>& that) const {
148    return !operator==(that);
149  }
150
151  /**
152   * Install a finalization callback on this object.
153   * NOTE: There is no guarantee as to *when* or even *if* the callback is
154   * invoked. The invocation is performed solely on a best effort basis.
155   * As always, GC-based finalization should *not* be relied upon for any
156   * critical form of resource management!
157   *
158   * The callback is supposed to reset the handle. No further V8 API may be
159   * called in this callback. In case additional work involving V8 needs to be
160   * done, a second callback can be scheduled using
161   * WeakCallbackInfo<void>::SetSecondPassCallback.
162   */
163  template <typename P>
164  V8_INLINE void SetWeak(P* parameter,
165                         typename WeakCallbackInfo<P>::Callback callback,
166                         WeakCallbackType type);
167
168  /**
169   * Turns this handle into a weak phantom handle without finalization callback.
170   * The handle will be reset automatically when the garbage collector detects
171   * that the object is no longer reachable.
172   * A related function Isolate::NumberOfPhantomHandleResetsSinceLastCall
173   * returns how many phantom handles were reset by the garbage collector.
174   */
175  V8_INLINE void SetWeak();
176
177  template <typename P>
178  V8_INLINE P* ClearWeak();
179
180  // TODO(dcarney): remove this.
181  V8_INLINE void ClearWeak() { ClearWeak<void>(); }
182
183  /**
184   * Annotates the strong handle with the given label, which is then used by the
185   * heap snapshot generator as a name of the edge from the root to the handle.
186   * The function does not take ownership of the label and assumes that the
187   * label is valid as long as the handle is valid.
188   */
189  V8_INLINE void AnnotateStrongRetainer(const char* label);
190
191  /** Returns true if the handle's reference is weak.  */
192  V8_INLINE bool IsWeak() const;
193
194  /**
195   * Assigns a wrapper class ID to the handle.
196   */
197  V8_INLINE void SetWrapperClassId(uint16_t class_id);
198
199  /**
200   * Returns the class ID previously assigned to this handle or 0 if no class ID
201   * was previously assigned.
202   */
203  V8_INLINE uint16_t WrapperClassId() const;
204
205  PersistentBase(const PersistentBase& other) = delete;
206  void operator=(const PersistentBase&) = delete;
207
208 private:
209  friend class Isolate;
210  friend class Utils;
211  template <class F>
212  friend class Local;
213  template <class F1, class F2>
214  friend class Persistent;
215  template <class F>
216  friend class Global;
217  template <class F>
218  friend class PersistentBase;
219  template <class F>
220  friend class ReturnValue;
221  template <class F1, class F2, class F3>
222  friend class PersistentValueMapBase;
223  template <class F1, class F2>
224  friend class PersistentValueVector;
225  friend class Object;
226
227  explicit V8_INLINE PersistentBase(T* val) : val_(val) {}
228  V8_INLINE static T* New(Isolate* isolate, T* that);
229
230  T* val_;
231};
232
233/**
234 * Default traits for Persistent. This class does not allow
235 * use of the copy constructor or assignment operator.
236 * At present kResetInDestructor is not set, but that will change in a future
237 * version.
238 */
239template <class T>
240class NonCopyablePersistentTraits {
241 public:
242  using NonCopyablePersistent = Persistent<T, NonCopyablePersistentTraits<T>>;
243  static const bool kResetInDestructor = false;
244  template <class S, class M>
245  V8_INLINE static void Copy(const Persistent<S, M>& source,
246                             NonCopyablePersistent* dest) {
247    static_assert(sizeof(S) < 0,
248                  "NonCopyablePersistentTraits::Copy is not instantiable");
249  }
250};
251
252/**
253 * Helper class traits to allow copying and assignment of Persistent.
254 * This will clone the contents of storage cell, but not any of the flags, etc.
255 */
256template <class T>
257struct CopyablePersistentTraits {
258  using CopyablePersistent = Persistent<T, CopyablePersistentTraits<T>>;
259  static const bool kResetInDestructor = true;
260  template <class S, class M>
261  static V8_INLINE void Copy(const Persistent<S, M>& source,
262                             CopyablePersistent* dest) {
263    // do nothing, just allow copy
264  }
265};
266
267/**
268 * A PersistentBase which allows copy and assignment.
269 *
270 * Copy, assignment and destructor behavior is controlled by the traits
271 * class M.
272 *
273 * Note: Persistent class hierarchy is subject to future changes.
274 */
275template <class T, class M>
276class Persistent : public PersistentBase<T> {
277 public:
278  /**
279   * A Persistent with no storage cell.
280   */
281  V8_INLINE Persistent() : PersistentBase<T>(nullptr) {}
282  /**
283   * Construct a Persistent from a Local.
284   * When the Local is non-empty, a new storage cell is created
285   * pointing to the same object, and no flags are set.
286   */
287  template <class S>
288  V8_INLINE Persistent(Isolate* isolate, Local<S> that)
289      : PersistentBase<T>(PersistentBase<T>::New(isolate, *that)) {
290    static_assert(std::is_base_of<T, S>::value, "type check");
291  }
292  /**
293   * Construct a Persistent from a Persistent.
294   * When the Persistent is non-empty, a new storage cell is created
295   * pointing to the same object, and no flags are set.
296   */
297  template <class S, class M2>
298  V8_INLINE Persistent(Isolate* isolate, const Persistent<S, M2>& that)
299      : PersistentBase<T>(PersistentBase<T>::New(isolate, *that)) {
300    static_assert(std::is_base_of<T, S>::value, "type check");
301  }
302  /**
303   * The copy constructors and assignment operator create a Persistent
304   * exactly as the Persistent constructor, but the Copy function from the
305   * traits class is called, allowing the setting of flags based on the
306   * copied Persistent.
307   */
308  V8_INLINE Persistent(const Persistent& that) : PersistentBase<T>(nullptr) {
309    Copy(that);
310  }
311  template <class S, class M2>
312  V8_INLINE Persistent(const Persistent<S, M2>& that) : PersistentBase<T>(0) {
313    Copy(that);
314  }
315  V8_INLINE Persistent& operator=(const Persistent& that) {
316    Copy(that);
317    return *this;
318  }
319  template <class S, class M2>
320  V8_INLINE Persistent& operator=(const Persistent<S, M2>& that) {
321    Copy(that);
322    return *this;
323  }
324  /**
325   * The destructor will dispose the Persistent based on the
326   * kResetInDestructor flags in the traits class.  Since not calling dispose
327   * can result in a memory leak, it is recommended to always set this flag.
328   */
329  V8_INLINE ~Persistent() {
330    if (M::kResetInDestructor) this->Reset();
331  }
332
333  // TODO(dcarney): this is pretty useless, fix or remove
334  template <class S>
335  V8_INLINE static Persistent<T>& Cast(const Persistent<S>& that) {
336#ifdef V8_ENABLE_CHECKS
337    // If we're going to perform the type check then we have to check
338    // that the handle isn't empty before doing the checked cast.
339    if (!that.IsEmpty()) T::Cast(*that);
340#endif
341    return reinterpret_cast<Persistent<T>&>(const_cast<Persistent<S>&>(that));
342  }
343
344  // TODO(dcarney): this is pretty useless, fix or remove
345  template <class S>
346  V8_INLINE Persistent<S>& As() const {
347    return Persistent<S>::Cast(*this);
348  }
349
350 private:
351  friend class Isolate;
352  friend class Utils;
353  template <class F>
354  friend class Local;
355  template <class F1, class F2>
356  friend class Persistent;
357  template <class F>
358  friend class ReturnValue;
359
360  explicit V8_INLINE Persistent(T* that) : PersistentBase<T>(that) {}
361  V8_INLINE T* operator*() const { return this->val_; }
362  template <class S, class M2>
363  V8_INLINE void Copy(const Persistent<S, M2>& that);
364};
365
366/**
367 * A PersistentBase which has move semantics.
368 *
369 * Note: Persistent class hierarchy is subject to future changes.
370 */
371template <class T>
372class Global : public PersistentBase<T> {
373 public:
374  /**
375   * A Global with no storage cell.
376   */
377  V8_INLINE Global() : PersistentBase<T>(nullptr) {}
378
379  /**
380   * Construct a Global from a Local.
381   * When the Local is non-empty, a new storage cell is created
382   * pointing to the same object, and no flags are set.
383   */
384  template <class S>
385  V8_INLINE Global(Isolate* isolate, Local<S> that)
386      : PersistentBase<T>(PersistentBase<T>::New(isolate, *that)) {
387    static_assert(std::is_base_of<T, S>::value, "type check");
388  }
389
390  /**
391   * Construct a Global from a PersistentBase.
392   * When the Persistent is non-empty, a new storage cell is created
393   * pointing to the same object, and no flags are set.
394   */
395  template <class S>
396  V8_INLINE Global(Isolate* isolate, const PersistentBase<S>& that)
397      : PersistentBase<T>(PersistentBase<T>::New(isolate, that.val_)) {
398    static_assert(std::is_base_of<T, S>::value, "type check");
399  }
400
401  /**
402   * Move constructor.
403   */
404  V8_INLINE Global(Global&& other);
405
406  V8_INLINE ~Global() { this->Reset(); }
407
408  /**
409   * Move via assignment.
410   */
411  template <class S>
412  V8_INLINE Global& operator=(Global<S>&& rhs);
413
414  /**
415   * Pass allows returning uniques from functions, etc.
416   */
417  Global Pass() { return static_cast<Global&&>(*this); }
418
419  /*
420   * For compatibility with Chromium's base::Bind (base::Passed).
421   */
422  using MoveOnlyTypeForCPP03 = void;
423
424  Global(const Global&) = delete;
425  void operator=(const Global&) = delete;
426
427 private:
428  template <class F>
429  friend class ReturnValue;
430  V8_INLINE T* operator*() const { return this->val_; }
431};
432
433// UniquePersistent is an alias for Global for historical reason.
434template <class T>
435using UniquePersistent = Global<T>;
436
437/**
438 * Interface for iterating through all the persistent handles in the heap.
439 */
440class V8_EXPORT PersistentHandleVisitor {
441 public:
442  virtual ~PersistentHandleVisitor() = default;
443  virtual void VisitPersistentHandle(Persistent<Value>* value,
444                                     uint16_t class_id) {}
445};
446
447template <class T>
448T* PersistentBase<T>::New(Isolate* isolate, T* that) {
449  if (that == nullptr) return nullptr;
450  internal::Address* p = reinterpret_cast<internal::Address*>(that);
451  return reinterpret_cast<T*>(api_internal::GlobalizeReference(
452      reinterpret_cast<internal::Isolate*>(isolate), p));
453}
454
455template <class T, class M>
456template <class S, class M2>
457void Persistent<T, M>::Copy(const Persistent<S, M2>& that) {
458  static_assert(std::is_base_of<T, S>::value, "type check");
459  this->Reset();
460  if (that.IsEmpty()) return;
461  internal::Address* p = reinterpret_cast<internal::Address*>(that.val_);
462  this->val_ = reinterpret_cast<T*>(api_internal::CopyGlobalReference(p));
463  M::Copy(that, this);
464}
465
466template <class T>
467bool PersistentBase<T>::IsWeak() const {
468  using I = internal::Internals;
469  if (this->IsEmpty()) return false;
470  return I::GetNodeState(reinterpret_cast<internal::Address*>(this->val_)) ==
471         I::kNodeStateIsWeakValue;
472}
473
474template <class T>
475void PersistentBase<T>::Reset() {
476  if (this->IsEmpty()) return;
477  api_internal::DisposeGlobal(reinterpret_cast<internal::Address*>(this->val_));
478  val_ = nullptr;
479}
480
481/**
482 * If non-empty, destroy the underlying storage cell
483 * and create a new one with the contents of other if other is non empty
484 */
485template <class T>
486template <class S>
487void PersistentBase<T>::Reset(Isolate* isolate, const Local<S>& other) {
488  static_assert(std::is_base_of<T, S>::value, "type check");
489  Reset();
490  if (other.IsEmpty()) return;
491  this->val_ = New(isolate, other.val_);
492}
493
494/**
495 * If non-empty, destroy the underlying storage cell
496 * and create a new one with the contents of other if other is non empty
497 */
498template <class T>
499template <class S>
500void PersistentBase<T>::Reset(Isolate* isolate,
501                              const PersistentBase<S>& other) {
502  static_assert(std::is_base_of<T, S>::value, "type check");
503  Reset();
504  if (other.IsEmpty()) return;
505  this->val_ = New(isolate, other.val_);
506}
507
508template <class T>
509template <typename P>
510V8_INLINE void PersistentBase<T>::SetWeak(
511    P* parameter, typename WeakCallbackInfo<P>::Callback callback,
512    WeakCallbackType type) {
513  using Callback = WeakCallbackInfo<void>::Callback;
514#if (__GNUC__ >= 8) && !defined(__clang__)
515#pragma GCC diagnostic push
516#pragma GCC diagnostic ignored "-Wcast-function-type"
517#endif
518  api_internal::MakeWeak(reinterpret_cast<internal::Address*>(this->val_),
519                         parameter, reinterpret_cast<Callback>(callback), type);
520#if (__GNUC__ >= 8) && !defined(__clang__)
521#pragma GCC diagnostic pop
522#endif
523}
524
525template <class T>
526void PersistentBase<T>::SetWeak() {
527  api_internal::MakeWeak(reinterpret_cast<internal::Address**>(&this->val_));
528}
529
530template <class T>
531template <typename P>
532P* PersistentBase<T>::ClearWeak() {
533  return reinterpret_cast<P*>(api_internal::ClearWeak(
534      reinterpret_cast<internal::Address*>(this->val_)));
535}
536
537template <class T>
538void PersistentBase<T>::AnnotateStrongRetainer(const char* label) {
539  api_internal::AnnotateStrongRetainer(
540      reinterpret_cast<internal::Address*>(this->val_), label);
541}
542
543template <class T>
544void PersistentBase<T>::SetWrapperClassId(uint16_t class_id) {
545  using I = internal::Internals;
546  if (this->IsEmpty()) return;
547  internal::Address* obj = reinterpret_cast<internal::Address*>(this->val_);
548  uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + I::kNodeClassIdOffset;
549  *reinterpret_cast<uint16_t*>(addr) = class_id;
550}
551
552template <class T>
553uint16_t PersistentBase<T>::WrapperClassId() const {
554  using I = internal::Internals;
555  if (this->IsEmpty()) return 0;
556  internal::Address* obj = reinterpret_cast<internal::Address*>(this->val_);
557  uint8_t* addr = reinterpret_cast<uint8_t*>(obj) + I::kNodeClassIdOffset;
558  return *reinterpret_cast<uint16_t*>(addr);
559}
560
561template <class T>
562Global<T>::Global(Global&& other) : PersistentBase<T>(other.val_) {
563  if (other.val_ != nullptr) {
564    api_internal::MoveGlobalReference(
565        reinterpret_cast<internal::Address**>(&other.val_),
566        reinterpret_cast<internal::Address**>(&this->val_));
567    other.val_ = nullptr;
568  }
569}
570
571template <class T>
572template <class S>
573Global<T>& Global<T>::operator=(Global<S>&& rhs) {
574  static_assert(std::is_base_of<T, S>::value, "type check");
575  if (this != &rhs) {
576    this->Reset();
577    if (rhs.val_ != nullptr) {
578      this->val_ = rhs.val_;
579      api_internal::MoveGlobalReference(
580          reinterpret_cast<internal::Address**>(&rhs.val_),
581          reinterpret_cast<internal::Address**>(&this->val_));
582      rhs.val_ = nullptr;
583    }
584  }
585  return *this;
586}
587
588}  // namespace v8
589
590#endif  // INCLUDE_V8_PERSISTENT_HANDLE_H_
591