// 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
#include
#include
#include "v8-handle-base.h" // NOLINT(build/include_directory)
#include "v8-internal.h" // NOLINT(build/include_directory)
namespace v8 {
template
class LocalBase;
template
class Local;
template
class LocalVector;
template
class MaybeLocal;
template
class Eternal;
template
class Global;
template
class NonCopyablePersistentTraits;
template
class PersistentBase;
template >
class Persistent;
class TracedReferenceBase;
template
class BasicTracedReference;
template
class TracedReference;
class Boolean;
class Context;
class EscapableHandleScope;
template
class FunctionCallbackInfo;
class Isolate;
class Object;
template
class PersistentValueMapBase;
template
class PersistentValueVector;
class Primitive;
class Private;
template
class PropertyCallbackInfo;
template
class ReturnValue;
class String;
template
class Traced;
class TypecheckWitness;
class Utils;
namespace debug {
class ConsoleCallArguments;
}
namespace internal {
template
class CustomArguments;
template
class LocalUnchecked;
class SamplingHeapProfiler;
} // 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(i_isolate_);
}
HandleScope(const HandleScope&) = delete;
void operator=(const HandleScope&) = delete;
static internal::Address* CreateHandleForCurrentIsolate(
internal::Address value);
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_;
#ifdef V8_ENABLE_CHECKS
int scope_level_ = 0;
#endif
// LocalBase::New uses CreateHandle with an Isolate* parameter.
template
friend class LocalBase;
// Object::GetInternalField and Context::GetEmbedderData use CreateHandle with
// a HeapObject in their shortcuts.
friend class Object;
friend class Context;
};
/**
* A base class for local handles.
* Its implementation depends on whether direct local support is enabled.
* When it is, a local handle contains a direct pointer to the referenced
* object, otherwise it contains an indirect pointer.
*/
#ifdef V8_ENABLE_DIRECT_LOCAL
template
class LocalBase : public api_internal::DirectHandleBase {
protected:
template
friend class Local;
V8_INLINE LocalBase() = default;
V8_INLINE explicit LocalBase(internal::Address ptr) : DirectHandleBase(ptr) {}
template
V8_INLINE LocalBase(const LocalBase& other) : DirectHandleBase(other) {}
V8_INLINE static LocalBase New(Isolate* isolate, internal::Address value) {
return LocalBase(value);
}
V8_INLINE static LocalBase New(Isolate* isolate, T* that) {
return LocalBase::New(isolate,
internal::ValueHelper::ValueAsAddress(that));
}
V8_INLINE static LocalBase FromSlot(internal::Address* slot) {
return LocalBase(*slot);
}
};
#else // !V8_ENABLE_DIRECT_LOCAL
template
class LocalBase : public api_internal::IndirectHandleBase {
protected:
template
friend class Local;
V8_INLINE LocalBase() = default;
V8_INLINE explicit LocalBase(internal::Address* location)
: IndirectHandleBase(location) {}
template
V8_INLINE LocalBase(const LocalBase& other) : IndirectHandleBase(other) {}
V8_INLINE static LocalBase New(Isolate* isolate, internal::Address value) {
return LocalBase(HandleScope::CreateHandle(
reinterpret_cast(isolate), value));
}
V8_INLINE static LocalBase New(Isolate* isolate, T* that) {
if (internal::ValueHelper::IsEmpty(that)) return LocalBase();
return LocalBase::New(isolate,
internal::ValueHelper::ValueAsAddress(that));
}
V8_INLINE static LocalBase FromSlot(internal::Address* slot) {
return LocalBase(slot);
}
};
#endif // V8_ENABLE_DIRECT_LOCAL
/**
* 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