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