v8-persistent-handle.h 19 KB

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