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
14namespace v8 {
15
16template <class T>
17class LocalBase;
18template <class T>
19class Local;
20template <class F>
21class MaybeLocal;
22
23template <class T>
24class Eternal;
25template <class T>
26class Global;
27
28template <class T>
29class NonCopyablePersistentTraits;
30template <class T>
31class PersistentBase;
32template <class T, class M = NonCopyablePersistentTraits<T>>
33class Persistent;
34
35class TracedReferenceBase;
36template <class T>
37class BasicTracedReference;
38template <class F>
39class TracedReference;
40
41class Boolean;
42class Context;
43class EscapableHandleScope;
44template <class F>
45class FunctionCallbackInfo;
46class Isolate;
47class Object;
48template <class F1, class F2, class F3>
49class PersistentValueMapBase;
50template <class F1, class F2>
51class PersistentValueVector;
52class Primitive;
53class Private;
54template <class F>
55class PropertyCallbackInfo;
56template <class F>
57class ReturnValue;
58class String;
59template <class F>
60class Traced;
61class Utils;
62
63namespace debug {
64class ConsoleCallArguments;
65}
66
67namespace internal {
68template <typename T>
69class CustomArguments;
70class SamplingHeapProfiler;
71}  // namespace internal
72
73namespace api_internal {
74// Called when ToLocalChecked is called on an empty Local.
75V8_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 */
92class 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
103  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
151template <typename T>
152class LocalBase : public DirectHandleBase {
153 protected:
154  template <class F>
155  friend class Local;
156
157  V8_INLINE LocalBase() = default;
158
159  V8_INLINE explicit LocalBase(internal::Address ptr) : DirectHandleBase(ptr) {}
160
161  template <typename S>
162  V8_INLINE LocalBase(const LocalBase<S>& other) : DirectHandleBase(other) {}
163
164  V8_INLINE static LocalBase<T> New(Isolate* isolate, internal::Address value) {
165    return LocalBase<T>(value);
166  }
167
168  V8_INLINE static LocalBase<T> New(Isolate* isolate, T* that) {
169    return LocalBase<T>::New(isolate,
170                             internal::ValueHelper::ValueAsAddress(that));
171  }
172
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
180template <typename T>
181class LocalBase : public IndirectHandleBase {
182 protected:
183  template <class F>
184  friend class Local;
185
186  V8_INLINE LocalBase() = default;
187
188  V8_INLINE explicit LocalBase(internal::Address* location)
189      : IndirectHandleBase(location) {}
190
191  template <typename S>
192  V8_INLINE LocalBase(const LocalBase<S>& other) : IndirectHandleBase(other) {}
193
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
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
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 */
241template <class T>
242class Local : public LocalBase<T> {
243 public:
244  V8_INLINE Local() = default;
245
246  template <class S>
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
256  V8_INLINE T* operator->() const { return this->template value<T>(); }
257
258  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>
272  V8_INLINE bool operator==(const Local<S>& that) const {
273    return internal::HandleHelper::EqualHandles(*this, that);
274  }
275
276  template <class S>
277  V8_INLINE bool operator==(const PersistentBase<S>& that) const {
278    return internal::HandleHelper::EqualHandles(*this, that);
279  }
280
281  template <class S>
282  V8_INLINE bool operator!=(const Local<S>& that) const {
283    return !operator==(that);
284  }
285
286  template <class S>
287  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>
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>
313  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   */
322  V8_INLINE static Local<T> New(Isolate* isolate, Local<T> that) {
323    return New(isolate, that.template value<T>());
324  }
325
326  V8_INLINE static Local<T> New(Isolate* isolate,
327                                const PersistentBase<T>& that) {
328    return New(isolate, that.template value<T>());
329  }
330
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
378  V8_INLINE explicit Local<T>(const LocalBase<T>& other)
379      : LocalBase<T>(other) {}
380
381  V8_INLINE static Local<T> FromSlot(internal::Address* slot) {
382    return Local<T>(LocalBase<T>::FromSlot(slot));
383  }
384
385  V8_INLINE static Local<T> New(Isolate* isolate, internal::Address value) {
386    return Local<T>(LocalBase<T>::New(isolate, value));
387  }
388
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>
395  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.
402template <class T>
403using 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 */
416template <class T>
417class MaybeLocal {
418 public:
419  V8_INLINE MaybeLocal() : local_() {}
420  template <class S>
421  V8_INLINE MaybeLocal(Local<S> that) : local_(that) {}
422
423  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>
430  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   */
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>
449  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 */
461class 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>
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>
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 */
504class 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