Update Files
This commit is contained in:
455
v8/include/v8-local-handle.h
Normal file
455
v8/include/v8-local-handle.h
Normal file
@ -0,0 +1,455 @@
|
||||
// Copyright 2021 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef INCLUDE_V8_LOCAL_HANDLE_H_
|
||||
#define INCLUDE_V8_LOCAL_HANDLE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "v8-internal.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace v8 {
|
||||
|
||||
class Boolean;
|
||||
template <class T>
|
||||
class BasicTracedReference;
|
||||
class Context;
|
||||
class EscapableHandleScope;
|
||||
template <class F>
|
||||
class Eternal;
|
||||
template <class F>
|
||||
class FunctionCallbackInfo;
|
||||
class Isolate;
|
||||
template <class F>
|
||||
class MaybeLocal;
|
||||
template <class T>
|
||||
class NonCopyablePersistentTraits;
|
||||
class Object;
|
||||
template <class T, class M = NonCopyablePersistentTraits<T>>
|
||||
class Persistent;
|
||||
template <class T>
|
||||
class PersistentBase;
|
||||
template <class F1, class F2, class F3>
|
||||
class PersistentValueMapBase;
|
||||
template <class F1, class F2>
|
||||
class PersistentValueVector;
|
||||
class Primitive;
|
||||
class Private;
|
||||
template <class F>
|
||||
class PropertyCallbackInfo;
|
||||
template <class F>
|
||||
class ReturnValue;
|
||||
class String;
|
||||
template <class F>
|
||||
class Traced;
|
||||
template <class F>
|
||||
class TracedReference;
|
||||
class TracedReferenceBase;
|
||||
class Utils;
|
||||
|
||||
namespace internal {
|
||||
template <typename T>
|
||||
class CustomArguments;
|
||||
} // namespace internal
|
||||
|
||||
namespace api_internal {
|
||||
// Called when ToLocalChecked is called on an empty Local.
|
||||
V8_EXPORT void ToLocalEmpty();
|
||||
} // namespace api_internal
|
||||
|
||||
/**
|
||||
* A stack-allocated class that governs a number of local handles.
|
||||
* After a handle scope has been created, all local handles will be
|
||||
* allocated within that handle scope until either the handle scope is
|
||||
* deleted or another handle scope is created. If there is already a
|
||||
* handle scope and a new one is created, all allocations will take
|
||||
* place in the new handle scope until it is deleted. After that,
|
||||
* new handles will again be allocated in the original handle scope.
|
||||
*
|
||||
* After the handle scope of a local handle has been deleted the
|
||||
* garbage collector will no longer track the object stored in the
|
||||
* handle and may deallocate it. The behavior of accessing a handle
|
||||
* for which the handle scope has been deleted is undefined.
|
||||
*/
|
||||
class V8_EXPORT V8_NODISCARD HandleScope {
|
||||
public:
|
||||
explicit HandleScope(Isolate* isolate);
|
||||
|
||||
~HandleScope();
|
||||
|
||||
/**
|
||||
* Counts the number of allocated handles.
|
||||
*/
|
||||
static int NumberOfHandles(Isolate* isolate);
|
||||
|
||||
V8_INLINE Isolate* GetIsolate() const {
|
||||
return reinterpret_cast<Isolate*>(i_isolate_);
|
||||
}
|
||||
|
||||
HandleScope(const HandleScope&) = delete;
|
||||
void operator=(const HandleScope&) = delete;
|
||||
|
||||
protected:
|
||||
V8_INLINE HandleScope() = default;
|
||||
|
||||
void Initialize(Isolate* isolate);
|
||||
|
||||
static internal::Address* CreateHandle(internal::Isolate* i_isolate,
|
||||
internal::Address value);
|
||||
|
||||
private:
|
||||
// Declaring operator new and delete as deleted is not spec compliant.
|
||||
// Therefore declare them private instead to disable dynamic alloc
|
||||
void* operator new(size_t size);
|
||||
void* operator new[](size_t size);
|
||||
void operator delete(void*, size_t);
|
||||
void operator delete[](void*, size_t);
|
||||
|
||||
internal::Isolate* i_isolate_;
|
||||
internal::Address* prev_next_;
|
||||
internal::Address* prev_limit_;
|
||||
|
||||
// Local::New uses CreateHandle with an Isolate* parameter.
|
||||
template <class F>
|
||||
friend class Local;
|
||||
|
||||
// Object::GetInternalField and Context::GetEmbedderData use CreateHandle with
|
||||
// a HeapObject in their shortcuts.
|
||||
friend class Object;
|
||||
friend class Context;
|
||||
};
|
||||
|
||||
/**
|
||||
* An object reference managed by the v8 garbage collector.
|
||||
*
|
||||
* All objects returned from v8 have to be tracked by the garbage collector so
|
||||
* that it knows that the objects are still alive. Also, because the garbage
|
||||
* collector may move objects, it is unsafe to point directly to an object.
|
||||
* Instead, all objects are stored in handles which are known by the garbage
|
||||
* collector and updated whenever an object moves. Handles should always be
|
||||
* passed by value (except in cases like out-parameters) and they should never
|
||||
* be allocated on the heap.
|
||||
*
|
||||
* There are two types of handles: local and persistent handles.
|
||||
*
|
||||
* Local handles are light-weight and transient and typically used in local
|
||||
* operations. They are managed by HandleScopes. That means that a HandleScope
|
||||
* must exist on the stack when they are created and that they are only valid
|
||||
* inside of the HandleScope active during their creation. For passing a local
|
||||
* handle to an outer HandleScope, an EscapableHandleScope and its Escape()
|
||||
* method must be used.
|
||||
*
|
||||
* Persistent handles can be used when storing objects across several
|
||||
* independent operations and have to be explicitly deallocated when they're no
|
||||
* longer used.
|
||||
*
|
||||
* It is safe to extract the object stored in the handle by dereferencing the
|
||||
* handle (for instance, to extract the Object* from a Local<Object>); the value
|
||||
* will still be governed by a handle behind the scenes and the same rules apply
|
||||
* to these values as to their handles.
|
||||
*/
|
||||
template <class T>
|
||||
class Local {
|
||||
public:
|
||||
V8_INLINE Local() : val_(nullptr) {}
|
||||
template <class S>
|
||||
V8_INLINE Local(Local<S> that) : val_(reinterpret_cast<T*>(*that)) {
|
||||
/**
|
||||
* This check fails when trying to convert between incompatible
|
||||
* handles. For example, converting from a Local<String> to a
|
||||
* Local<Number>.
|
||||
*/
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the handle is empty.
|
||||
*/
|
||||
V8_INLINE bool IsEmpty() const { return val_ == nullptr; }
|
||||
|
||||
/**
|
||||
* Sets the handle to be empty. IsEmpty() will then return true.
|
||||
*/
|
||||
V8_INLINE void Clear() { val_ = nullptr; }
|
||||
|
||||
V8_INLINE T* operator->() const { return val_; }
|
||||
|
||||
V8_INLINE T* operator*() const { return val_; }
|
||||
|
||||
/**
|
||||
* Checks whether two handles are the same.
|
||||
* Returns true if both are empty, or if the objects to which they refer
|
||||
* are identical.
|
||||
*
|
||||
* If both handles refer to JS objects, this is the same as strict equality.
|
||||
* For primitives, such as numbers or strings, a `false` return value does not
|
||||
* indicate that the values aren't equal in the JavaScript sense.
|
||||
* Use `Value::StrictEquals()` to check primitives for equality.
|
||||
*/
|
||||
template <class S>
|
||||
V8_INLINE bool operator==(const Local<S>& that) const {
|
||||
internal::Address* a = reinterpret_cast<internal::Address*>(this->val_);
|
||||
internal::Address* b = reinterpret_cast<internal::Address*>(that.val_);
|
||||
if (a == nullptr) return b == nullptr;
|
||||
if (b == nullptr) return false;
|
||||
return *a == *b;
|
||||
}
|
||||
|
||||
template <class S>
|
||||
V8_INLINE bool operator==(const PersistentBase<S>& that) const {
|
||||
internal::Address* a = reinterpret_cast<internal::Address*>(this->val_);
|
||||
internal::Address* b = reinterpret_cast<internal::Address*>(that.val_);
|
||||
if (a == nullptr) return b == nullptr;
|
||||
if (b == nullptr) return false;
|
||||
return *a == *b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether two handles are different.
|
||||
* Returns true if only one of the handles is empty, or if
|
||||
* the objects to which they refer are different.
|
||||
*
|
||||
* If both handles refer to JS objects, this is the same as strict
|
||||
* non-equality. For primitives, such as numbers or strings, a `true` return
|
||||
* value does not indicate that the values aren't equal in the JavaScript
|
||||
* sense. Use `Value::StrictEquals()` to check primitives for equality.
|
||||
*/
|
||||
template <class S>
|
||||
V8_INLINE bool operator!=(const Local<S>& that) const {
|
||||
return !operator==(that);
|
||||
}
|
||||
|
||||
template <class S>
|
||||
V8_INLINE bool operator!=(const Persistent<S>& that) const {
|
||||
return !operator==(that);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast a handle to a subclass, e.g. Local<Value> to Local<Object>.
|
||||
* This is only valid if the handle actually refers to a value of the
|
||||
* target type.
|
||||
*/
|
||||
template <class S>
|
||||
V8_INLINE static Local<T> Cast(Local<S> that) {
|
||||
#ifdef V8_ENABLE_CHECKS
|
||||
// If we're going to perform the type check then we have to check
|
||||
// that the handle isn't empty before doing the checked cast.
|
||||
if (that.IsEmpty()) return Local<T>();
|
||||
#endif
|
||||
return Local<T>(T::Cast(*that));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calling this is equivalent to Local<S>::Cast().
|
||||
* In particular, this is only valid if the handle actually refers to a value
|
||||
* of the target type.
|
||||
*/
|
||||
template <class S>
|
||||
V8_INLINE Local<S> As() const {
|
||||
return Local<S>::Cast(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a local handle for the content of another handle.
|
||||
* The referee is kept alive by the local handle even when
|
||||
* the original handle is destroyed/disposed.
|
||||
*/
|
||||
V8_INLINE static Local<T> New(Isolate* isolate, Local<T> that) {
|
||||
return New(isolate, that.val_);
|
||||
}
|
||||
|
||||
V8_INLINE static Local<T> New(Isolate* isolate,
|
||||
const PersistentBase<T>& that) {
|
||||
return New(isolate, that.val_);
|
||||
}
|
||||
|
||||
V8_INLINE static Local<T> New(Isolate* isolate,
|
||||
const BasicTracedReference<T>& that) {
|
||||
return New(isolate, *that);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class TracedReferenceBase;
|
||||
friend class Utils;
|
||||
template <class F>
|
||||
friend class Eternal;
|
||||
template <class F>
|
||||
friend class PersistentBase;
|
||||
template <class F, class M>
|
||||
friend class Persistent;
|
||||
template <class F>
|
||||
friend class Local;
|
||||
template <class F>
|
||||
friend class MaybeLocal;
|
||||
template <class F>
|
||||
friend class FunctionCallbackInfo;
|
||||
template <class F>
|
||||
friend class PropertyCallbackInfo;
|
||||
friend class String;
|
||||
friend class Object;
|
||||
friend class Context;
|
||||
friend class Isolate;
|
||||
friend class Private;
|
||||
template <class F>
|
||||
friend class internal::CustomArguments;
|
||||
friend Local<Primitive> Undefined(Isolate* isolate);
|
||||
friend Local<Primitive> Null(Isolate* isolate);
|
||||
friend Local<Boolean> True(Isolate* isolate);
|
||||
friend Local<Boolean> False(Isolate* isolate);
|
||||
friend class HandleScope;
|
||||
friend class EscapableHandleScope;
|
||||
template <class F1, class F2, class F3>
|
||||
friend class PersistentValueMapBase;
|
||||
template <class F1, class F2>
|
||||
friend class PersistentValueVector;
|
||||
template <class F>
|
||||
friend class ReturnValue;
|
||||
template <class F>
|
||||
friend class Traced;
|
||||
template <class F>
|
||||
friend class BasicTracedReference;
|
||||
template <class F>
|
||||
friend class TracedReference;
|
||||
|
||||
explicit V8_INLINE Local(T* that) : val_(that) {}
|
||||
V8_INLINE static Local<T> New(Isolate* isolate, T* that) {
|
||||
if (that == nullptr) return Local<T>();
|
||||
T* that_ptr = that;
|
||||
internal::Address* p = reinterpret_cast<internal::Address*>(that_ptr);
|
||||
return Local<T>(reinterpret_cast<T*>(HandleScope::CreateHandle(
|
||||
reinterpret_cast<internal::Isolate*>(isolate), *p)));
|
||||
}
|
||||
T* val_;
|
||||
};
|
||||
|
||||
#if !defined(V8_IMMINENT_DEPRECATION_WARNINGS)
|
||||
// Handle is an alias for Local for historical reasons.
|
||||
template <class T>
|
||||
using Handle = Local<T>;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A MaybeLocal<> is a wrapper around Local<> that enforces a check whether
|
||||
* the Local<> is empty before it can be used.
|
||||
*
|
||||
* If an API method returns a MaybeLocal<>, the API method can potentially fail
|
||||
* either because an exception is thrown, or because an exception is pending,
|
||||
* e.g. because a previous API call threw an exception that hasn't been caught
|
||||
* yet, or because a TerminateExecution exception was thrown. In that case, an
|
||||
* empty MaybeLocal is returned.
|
||||
*/
|
||||
template <class T>
|
||||
class MaybeLocal {
|
||||
public:
|
||||
V8_INLINE MaybeLocal() : val_(nullptr) {}
|
||||
template <class S>
|
||||
V8_INLINE MaybeLocal(Local<S> that) : val_(reinterpret_cast<T*>(*that)) {
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
}
|
||||
|
||||
V8_INLINE bool IsEmpty() const { return val_ == nullptr; }
|
||||
|
||||
/**
|
||||
* Converts this MaybeLocal<> to a Local<>. If this MaybeLocal<> is empty,
|
||||
* |false| is returned and |out| is assigned with nullptr.
|
||||
*/
|
||||
template <class S>
|
||||
V8_WARN_UNUSED_RESULT V8_INLINE bool ToLocal(Local<S>* out) const {
|
||||
out->val_ = IsEmpty() ? nullptr : this->val_;
|
||||
return !IsEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this MaybeLocal<> to a Local<>. If this MaybeLocal<> is empty,
|
||||
* V8 will crash the process.
|
||||
*/
|
||||
V8_INLINE Local<T> ToLocalChecked() {
|
||||
if (V8_UNLIKELY(val_ == nullptr)) api_internal::ToLocalEmpty();
|
||||
return Local<T>(val_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this MaybeLocal<> to a Local<>, using a default value if this
|
||||
* MaybeLocal<> is empty.
|
||||
*/
|
||||
template <class S>
|
||||
V8_INLINE Local<S> FromMaybe(Local<S> default_value) const {
|
||||
return IsEmpty() ? default_value : Local<S>(val_);
|
||||
}
|
||||
|
||||
private:
|
||||
T* val_;
|
||||
};
|
||||
|
||||
/**
|
||||
* A HandleScope which first allocates a handle in the current scope
|
||||
* which will be later filled with the escape value.
|
||||
*/
|
||||
class V8_EXPORT V8_NODISCARD EscapableHandleScope : public HandleScope {
|
||||
public:
|
||||
explicit EscapableHandleScope(Isolate* isolate);
|
||||
V8_INLINE ~EscapableHandleScope() = default;
|
||||
|
||||
/**
|
||||
* Pushes the value into the previous scope and returns a handle to it.
|
||||
* Cannot be called twice.
|
||||
*/
|
||||
template <class T>
|
||||
V8_INLINE Local<T> Escape(Local<T> value) {
|
||||
internal::Address* slot =
|
||||
Escape(reinterpret_cast<internal::Address*>(*value));
|
||||
return Local<T>(reinterpret_cast<T*>(slot));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
V8_INLINE MaybeLocal<T> EscapeMaybe(MaybeLocal<T> value) {
|
||||
return Escape(value.FromMaybe(Local<T>()));
|
||||
}
|
||||
|
||||
EscapableHandleScope(const EscapableHandleScope&) = delete;
|
||||
void operator=(const EscapableHandleScope&) = delete;
|
||||
|
||||
private:
|
||||
// Declaring operator new and delete as deleted is not spec compliant.
|
||||
// Therefore declare them private instead to disable dynamic alloc
|
||||
void* operator new(size_t size);
|
||||
void* operator new[](size_t size);
|
||||
void operator delete(void*, size_t);
|
||||
void operator delete[](void*, size_t);
|
||||
|
||||
internal::Address* Escape(internal::Address* escape_value);
|
||||
internal::Address* escape_slot_;
|
||||
};
|
||||
|
||||
/**
|
||||
* A SealHandleScope acts like a handle scope in which no handle allocations
|
||||
* are allowed. It can be useful for debugging handle leaks.
|
||||
* Handles can be allocated within inner normal HandleScopes.
|
||||
*/
|
||||
class V8_EXPORT V8_NODISCARD SealHandleScope {
|
||||
public:
|
||||
explicit SealHandleScope(Isolate* isolate);
|
||||
~SealHandleScope();
|
||||
|
||||
SealHandleScope(const SealHandleScope&) = delete;
|
||||
void operator=(const SealHandleScope&) = delete;
|
||||
|
||||
private:
|
||||
// Declaring operator new and delete as deleted is not spec compliant.
|
||||
// Therefore declare them private instead to disable dynamic alloc
|
||||
void* operator new(size_t size);
|
||||
void* operator new[](size_t size);
|
||||
void operator delete(void*, size_t);
|
||||
void operator delete[](void*, size_t);
|
||||
|
||||
internal::Isolate* const i_isolate_;
|
||||
internal::Address* prev_limit_;
|
||||
int prev_sealed_level_;
|
||||
};
|
||||
|
||||
} // namespace v8
|
||||
|
||||
#endif // INCLUDE_V8_LOCAL_HANDLE_H_
|
Reference in New Issue
Block a user