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_LOCAL_HANDLE_H_
6 #define INCLUDE_V8_LOCAL_HANDLE_H_
7 
8 #include <stddef.h>
9 
10 #include <type_traits>
11 
12 #include "v8-handle-base.h"  // NOLINT(build/include_directory)
13 
14 namespace v8 {
15 
16 template <class T>
17 class LocalBase;
18 template <class T>
19 class Local;
20 template <class F>
21 class MaybeLocal;
22 
23 template <class T>
24 class Eternal;
25 template <class T>
26 class Global;
27 
28 template <class T>
29 class NonCopyablePersistentTraits;
30 template <class T>
31 class PersistentBase;
32 template <class T, class M = NonCopyablePersistentTraits<T>>
33 class Persistent;
34 
35 class TracedReferenceBase;
36 template <class T>
37 class BasicTracedReference;
38 template <class F>
39 class TracedReference;
40 
41 class Boolean;
42 class Context;
43 class EscapableHandleScope;
44 template <class F>
45 class FunctionCallbackInfo;
46 class Isolate;
47 class Object;
48 template <class F1, class F2, class F3>
49 class PersistentValueMapBase;
50 template <class F1, class F2>
51 class PersistentValueVector;
52 class Primitive;
53 class Private;
54 template <class F>
55 class PropertyCallbackInfo;
56 template <class F>
57 class ReturnValue;
58 class String;
59 template <class F>
60 class Traced;
61 class Utils;
62 
63 namespace debug {
64 class ConsoleCallArguments;
65 }
66 
67 namespace internal {
68 template <typename T>
69 class CustomArguments;
70 class SamplingHeapProfiler;
71 }  // namespace internal
72 
73 namespace api_internal {
74 // Called when ToLocalChecked is called on an empty Local.
75 V8_EXPORT void ToLocalEmpty();
76 }  // namespace api_internal
77 
78 /**
79  * A stack-allocated class that governs a number of local handles.
80  * After a handle scope has been created, all local handles will be
81  * allocated within that handle scope until either the handle scope is
82  * deleted or another handle scope is created.  If there is already a
83  * handle scope and a new one is created, all allocations will take
84  * place in the new handle scope until it is deleted.  After that,
85  * new handles will again be allocated in the original handle scope.
86  *
87  * After the handle scope of a local handle has been deleted the
88  * garbage collector will no longer track the object stored in the
89  * handle and may deallocate it.  The behavior of accessing a handle
90  * for which the handle scope has been deleted is undefined.
91  */
92 class V8_EXPORT V8_NODISCARD HandleScope {
93  public:
94   explicit HandleScope(Isolate* isolate);
95 
96   ~HandleScope();
97 
98   /**
99    * Counts the number of allocated handles.
100    */
101   static int NumberOfHandles(Isolate* isolate);
102 
GetIsolate() const103   V8_INLINE Isolate* GetIsolate() const {
104     return reinterpret_cast<Isolate*>(i_isolate_);
105   }
106 
107   HandleScope(const HandleScope&) = delete;
108   void operator=(const HandleScope&) = delete;
109 
110   static internal::Address* CreateHandleForCurrentIsolate(
111       internal::Address value);
112 
113  protected:
114   V8_INLINE HandleScope() = default;
115 
116   void Initialize(Isolate* isolate);
117 
118   static internal::Address* CreateHandle(internal::Isolate* i_isolate,
119                                          internal::Address value);
120 
121  private:
122   // Declaring operator new and delete as deleted is not spec compliant.
123   // Therefore declare them private instead to disable dynamic alloc
124   void* operator new(size_t size);
125   void* operator new[](size_t size);
126   void operator delete(void*, size_t);
127   void operator delete[](void*, size_t);
128 
129   internal::Isolate* i_isolate_;
130   internal::Address* prev_next_;
131   internal::Address* prev_limit_;
132 
133   // LocalBase<T>::New uses CreateHandle with an Isolate* parameter.
134   template <typename T>
135   friend class LocalBase;
136 
137   // Object::GetInternalField and Context::GetEmbedderData use CreateHandle with
138   // a HeapObject in their shortcuts.
139   friend class Object;
140   friend class Context;
141 };
142 
143 /**
144  * A base class for local handles.
145  * Its implementation depends on whether direct local support is enabled.
146  * When it is, a local handle contains a direct pointer to the referenced
147  * object, otherwise it contains an indirect pointer.
148  */
149 #ifdef V8_ENABLE_DIRECT_LOCAL
150 
151 template <typename T>
152 class LocalBase : public DirectHandleBase {
153  protected:
154   template <class F>
155   friend class Local;
156 
157   V8_INLINE LocalBase() = default;
158 
LocalBase(internal::Address ptr)159   V8_INLINE explicit LocalBase(internal::Address ptr) : DirectHandleBase(ptr) {}
160 
161   template <typename S>
LocalBase(const LocalBase<S>& other)162   V8_INLINE LocalBase(const LocalBase<S>& other) : DirectHandleBase(other) {}
163 
New(Isolate* isolate, internal::Address value)164   V8_INLINE static LocalBase<T> New(Isolate* isolate, internal::Address value) {
165     return LocalBase<T>(value);
166   }
167 
New(Isolate* isolate, T* that)168   V8_INLINE static LocalBase<T> New(Isolate* isolate, T* that) {
169     return LocalBase<T>::New(isolate,
170                              internal::ValueHelper::ValueAsAddress(that));
171   }
172 
FromSlot(internal::Address* slot)173   V8_INLINE static LocalBase<T> FromSlot(internal::Address* slot) {
174     return LocalBase<T>(*slot);
175   }
176 };
177 
178 #else  // !V8_ENABLE_DIRECT_LOCAL
179 
180 template <typename T>
181 class LocalBase : public IndirectHandleBase {
182  protected:
183   template <class F>
184   friend class Local;
185 
186   V8_INLINE LocalBase() = default;
187 
LocalBase(internal::Address* location)188   V8_INLINE explicit LocalBase(internal::Address* location)
189       : IndirectHandleBase(location) {}
190 
191   template <typename S>
LocalBase(const LocalBase<S>& other)192   V8_INLINE LocalBase(const LocalBase<S>& other) : IndirectHandleBase(other) {}
193 
New(Isolate* isolate, internal::Address value)194   V8_INLINE static LocalBase<T> New(Isolate* isolate, internal::Address value) {
195     return LocalBase(HandleScope::CreateHandle(
196         reinterpret_cast<internal::Isolate*>(isolate), value));
197   }
198 
New(Isolate* isolate, T* that)199   V8_INLINE static LocalBase<T> New(Isolate* isolate, T* that) {
200     if (internal::ValueHelper::IsEmpty(that)) return LocalBase<T>();
201     return LocalBase<T>::New(isolate,
202                              internal::ValueHelper::ValueAsAddress(that));
203   }
204 
FromSlot(internal::Address* slot)205   V8_INLINE static LocalBase<T> FromSlot(internal::Address* slot) {
206     return LocalBase<T>(slot);
207   }
208 };
209 
210 #endif  // V8_ENABLE_DIRECT_LOCAL
211 
212 /**
213  * An object reference managed by the v8 garbage collector.
214  *
215  * All objects returned from v8 have to be tracked by the garbage collector so
216  * that it knows that the objects are still alive.  Also, because the garbage
217  * collector may move objects, it is unsafe to point directly to an object.
218  * Instead, all objects are stored in handles which are known by the garbage
219  * collector and updated whenever an object moves.  Handles should always be
220  * passed by value (except in cases like out-parameters) and they should never
221  * be allocated on the heap.
222  *
223  * There are two types of handles: local and persistent handles.
224  *
225  * Local handles are light-weight and transient and typically used in local
226  * operations.  They are managed by HandleScopes. That means that a HandleScope
227  * must exist on the stack when they are created and that they are only valid
228  * inside of the HandleScope active during their creation. For passing a local
229  * handle to an outer HandleScope, an EscapableHandleScope and its Escape()
230  * method must be used.
231  *
232  * Persistent handles can be used when storing objects across several
233  * independent operations and have to be explicitly deallocated when they're no
234  * longer used.
235  *
236  * It is safe to extract the object stored in the handle by dereferencing the
237  * handle (for instance, to extract the Object* from a Local<Object>); the value
238  * will still be governed by a handle behind the scenes and the same rules apply
239  * to these values as to their handles.
240  */
241 template <class T>
242 class Local : public LocalBase<T> {
243  public:
244   V8_INLINE Local() = default;
245 
246   template <class S>
Local(Local<S> that)247   V8_INLINE Local(Local<S> that) : LocalBase<T>(that) {
248     /**
249      * This check fails when trying to convert between incompatible
250      * handles. For example, converting from a Local<String> to a
251      * Local<Number>.
252      */
253     static_assert(std::is_base_of<T, S>::value, "type check");
254   }
255 
operator ->() const256   V8_INLINE T* operator->() const { return this->template value<T>(); }
257 
operator *() const258   V8_INLINE T* operator*() const { return this->operator->(); }
259 
260   /**
261    * Checks whether two handles are equal or different.
262    * They are equal iff they are both empty or they are both non-empty and the
263    * objects to which they refer are physically equal.
264    *
265    * If both handles refer to JS objects, this is the same as strict
266    * non-equality. For primitives, such as numbers or strings, a `true` return
267    * value does not indicate that the values aren't equal in the JavaScript
268    * sense. Use `Value::StrictEquals()` to check primitives for equality.
269    */
270 
271   template <class S>
operator ==(const Local<S>& that) const272   V8_INLINE bool operator==(const Local<S>& that) const {
273     return internal::HandleHelper::EqualHandles(*this, that);
274   }
275 
276   template <class S>
operator ==(const PersistentBase<S>& that) const277   V8_INLINE bool operator==(const PersistentBase<S>& that) const {
278     return internal::HandleHelper::EqualHandles(*this, that);
279   }
280 
281   template <class S>
operator !=(const Local<S>& that) const282   V8_INLINE bool operator!=(const Local<S>& that) const {
283     return !operator==(that);
284   }
285 
286   template <class S>
operator !=(const Persistent<S>& that) const287   V8_INLINE bool operator!=(const Persistent<S>& that) const {
288     return !operator==(that);
289   }
290 
291   /**
292    * Cast a handle to a subclass, e.g. Local<Value> to Local<Object>.
293    * This is only valid if the handle actually refers to a value of the
294    * target type.
295    */
296   template <class S>
Cast(Local<S> that)297   V8_INLINE static Local<T> Cast(Local<S> that) {
298 #ifdef V8_ENABLE_CHECKS
299     // If we're going to perform the type check then we have to check
300     // that the handle isn't empty before doing the checked cast.
301     if (that.IsEmpty()) return Local<T>();
302     T::Cast(that.template value<S>());
303 #endif
304     return Local<T>(LocalBase<T>(that));
305   }
306 
307   /**
308    * Calling this is equivalent to Local<S>::Cast().
309    * In particular, this is only valid if the handle actually refers to a value
310    * of the target type.
311    */
312   template <class S>
As() const313   V8_INLINE Local<S> As() const {
314     return Local<S>::Cast(*this);
315   }
316 
317   /**
318    * Create a local handle for the content of another handle.
319    * The referee is kept alive by the local handle even when
320    * the original handle is destroyed/disposed.
321    */
New(Isolate* isolate, Local<T> that)322   V8_INLINE static Local<T> New(Isolate* isolate, Local<T> that) {
323     return New(isolate, that.template value<T>());
324   }
325 
New(Isolate* isolate, const PersistentBase<T>& that)326   V8_INLINE static Local<T> New(Isolate* isolate,
327                                 const PersistentBase<T>& that) {
328     return New(isolate, that.template value<T>());
329   }
330 
New(Isolate* isolate, const BasicTracedReference<T>& that)331   V8_INLINE static Local<T> New(Isolate* isolate,
332                                 const BasicTracedReference<T>& that) {
333     return New(isolate, that.template value<T>());
334   }
335 
336  private:
337   friend class TracedReferenceBase;
338   friend class Utils;
339   template <class F>
340   friend class Eternal;
341   template <class F>
342   friend class Global;
343   template <class F>
344   friend class Local;
345   template <class F>
346   friend class MaybeLocal;
347   template <class F, class M>
348   friend class Persistent;
349   template <class F>
350   friend class FunctionCallbackInfo;
351   template <class F>
352   friend class PropertyCallbackInfo;
353   friend class String;
354   friend class Object;
355   friend class Context;
356   friend class Isolate;
357   friend class Private;
358   template <class F>
359   friend class internal::CustomArguments;
360   friend Local<Primitive> Undefined(Isolate* isolate);
361   friend Local<Primitive> Null(Isolate* isolate);
362   friend Local<Boolean> True(Isolate* isolate);
363   friend Local<Boolean> False(Isolate* isolate);
364   friend class HandleScope;
365   friend class EscapableHandleScope;
366   template <class F1, class F2, class F3>
367   friend class PersistentValueMapBase;
368   template <class F1, class F2>
369   friend class PersistentValueVector;
370   template <class F>
371   friend class ReturnValue;
372   template <class F>
373   friend class Traced;
374   friend class internal::SamplingHeapProfiler;
375   friend class internal::HandleHelper;
376   friend class debug::ConsoleCallArguments;
377 
Local(const LocalBase<T>& other)378   V8_INLINE explicit Local<T>(const LocalBase<T>& other)
379       : LocalBase<T>(other) {}
380 
FromSlot(internal::Address* slot)381   V8_INLINE static Local<T> FromSlot(internal::Address* slot) {
382     return Local<T>(LocalBase<T>::FromSlot(slot));
383   }
384 
New(Isolate* isolate, internal::Address value)385   V8_INLINE static Local<T> New(Isolate* isolate, internal::Address value) {
386     return Local<T>(LocalBase<T>::New(isolate, value));
387   }
388 
New(Isolate* isolate, T* that)389   V8_INLINE static Local<T> New(Isolate* isolate, T* that) {
390     return Local<T>(LocalBase<T>::New(isolate, that));
391   }
392 
393   // Unsafe cast, should be avoided.
394   template <class S>
UnsafeAs() const395   V8_INLINE Local<S> UnsafeAs() const {
396     return Local<S>(LocalBase<S>(*this));
397   }
398 };
399 
400 #if !defined(V8_IMMINENT_DEPRECATION_WARNINGS)
401 // Handle is an alias for Local for historical reasons.
402 template <class T>
403 using Handle = Local<T>;
404 #endif
405 
406 /**
407  * A MaybeLocal<> is a wrapper around Local<> that enforces a check whether
408  * the Local<> is empty before it can be used.
409  *
410  * If an API method returns a MaybeLocal<>, the API method can potentially fail
411  * either because an exception is thrown, or because an exception is pending,
412  * e.g. because a previous API call threw an exception that hasn't been caught
413  * yet, or because a TerminateExecution exception was thrown. In that case, an
414  * empty MaybeLocal is returned.
415  */
416 template <class T>
417 class MaybeLocal {
418  public:
MaybeLocal()419   V8_INLINE MaybeLocal() : local_() {}
420   template <class S>
MaybeLocal(Local<S> that)421   V8_INLINE MaybeLocal(Local<S> that) : local_(that) {}
422 
IsEmpty() const423   V8_INLINE bool IsEmpty() const { return local_.IsEmpty(); }
424 
425   /**
426    * Converts this MaybeLocal<> to a Local<>. If this MaybeLocal<> is empty,
427    * |false| is returned and |out| is assigned with nullptr.
428    */
429   template <class S>
ToLocal(Local<S>* out) const430   V8_WARN_UNUSED_RESULT V8_INLINE bool ToLocal(Local<S>* out) const {
431     *out = local_;
432     return !IsEmpty();
433   }
434 
435   /**
436    * Converts this MaybeLocal<> to a Local<>. If this MaybeLocal<> is empty,
437    * V8 will crash the process.
438    */
ToLocalChecked()439   V8_INLINE Local<T> ToLocalChecked() {
440     if (V8_UNLIKELY(IsEmpty())) api_internal::ToLocalEmpty();
441     return local_;
442   }
443 
444   /**
445    * Converts this MaybeLocal<> to a Local<>, using a default value if this
446    * MaybeLocal<> is empty.
447    */
448   template <class S>
FromMaybe(Local<S> default_value) const449   V8_INLINE Local<S> FromMaybe(Local<S> default_value) const {
450     return IsEmpty() ? default_value : Local<S>(local_);
451   }
452 
453  private:
454   Local<T> local_;
455 };
456 
457 /**
458  * A HandleScope which first allocates a handle in the current scope
459  * which will be later filled with the escape value.
460  */
461 class V8_EXPORT V8_NODISCARD EscapableHandleScope : public HandleScope {
462  public:
463   explicit EscapableHandleScope(Isolate* isolate);
464   V8_INLINE ~EscapableHandleScope() = default;
465 
466   /**
467    * Pushes the value into the previous scope and returns a handle to it.
468    * Cannot be called twice.
469    */
470   template <class T>
Escape(Local<T> value)471   V8_INLINE Local<T> Escape(Local<T> value) {
472 #ifdef V8_ENABLE_DIRECT_LOCAL
473     return value;
474 #else
475     return Local<T>::FromSlot(Escape(value.slot()));
476 #endif
477   }
478 
479   template <class T>
EscapeMaybe(MaybeLocal<T> value)480   V8_INLINE MaybeLocal<T> EscapeMaybe(MaybeLocal<T> value) {
481     return Escape(value.FromMaybe(Local<T>()));
482   }
483 
484   EscapableHandleScope(const EscapableHandleScope&) = delete;
485   void operator=(const EscapableHandleScope&) = delete;
486 
487  private:
488   // Declaring operator new and delete as deleted is not spec compliant.
489   // Therefore declare them private instead to disable dynamic alloc
490   void* operator new(size_t size);
491   void* operator new[](size_t size);
492   void operator delete(void*, size_t);
493   void operator delete[](void*, size_t);
494 
495   internal::Address* Escape(internal::Address* escape_value);
496   internal::Address* escape_slot_;
497 };
498 
499 /**
500  * A SealHandleScope acts like a handle scope in which no handle allocations
501  * are allowed. It can be useful for debugging handle leaks.
502  * Handles can be allocated within inner normal HandleScopes.
503  */
504 class V8_EXPORT V8_NODISCARD SealHandleScope {
505  public:
506   explicit SealHandleScope(Isolate* isolate);
507   ~SealHandleScope();
508 
509   SealHandleScope(const SealHandleScope&) = delete;
510   void operator=(const SealHandleScope&) = delete;
511 
512  private:
513   // Declaring operator new and delete as deleted is not spec compliant.
514   // Therefore declare them private instead to disable dynamic alloc
515   void* operator new(size_t size);
516   void* operator new[](size_t size);
517   void operator delete(void*, size_t);
518   void operator delete[](void*, size_t);
519 
520   internal::Isolate* const i_isolate_;
521   internal::Address* prev_limit_;
522   int prev_sealed_level_;
523 };
524 
525 }  // namespace v8
526 
527 #endif  // INCLUDE_V8_LOCAL_HANDLE_H_
528