#ifndef V8_HANDLES_HANDLES_H_
#define V8_HANDLES_HANDLES_H_
#include <type_traits>
#include <vector>
#include "src/base/functional.h"
#include "src/base/macros.h"
#include "src/common/checks.h"
#include "src/common/globals.h"
#include "src/objects/casting.h"
#include "src/objects/tagged.h"
#include "v8-handle-base.h"
#ifdef V8_ENABLE_DIRECT_HANDLE
#include "src/flags/flags.h"
#endif
namespace v8 {
class HandleScope;
namespace internal {
#ifdef V8_ENABLE_DIRECT_HANDLE
class DirectHandleBase;
template <typename T>
class DirectHandleUnchecked;
#endif
class HandleScopeImplementer;
class Isolate;
class LocalHeap;
class LocalIsolate;
class TaggedIndex;
class Object;
class OrderedHashMap;
class OrderedHashSet;
class OrderedNameDictionary;
class RootVisitor;
class SmallOrderedHashMap;
class SmallOrderedHashSet;
class SmallOrderedNameDictionary;
class SwissNameDictionary;
class WasmExportedFunctionData;
class ZoneAllocationPolicy;
constexpr Address kTaggedNullAddress = …;
class HandleBase { … };
template <typename T>
class Handle final : public HandleBase { … };
template <typename T>
std::ostream& operator<<(std::ostream& os, Handle<T> handle);
class V8_NODISCARD HandleScope { … };
template <typename V, class AllocationPolicy>
class IdentityMap;
CanonicalHandlesMap;
class V8_NODISCARD SealHandleScope final { … };
struct HandleScopeData final { … };
static_assert …;
#ifdef V8_ENABLE_DIRECT_HANDLE
static_assert(V8_ENABLE_CONSERVATIVE_STACK_SCANNING_BOOL);
class V8_TRIVIAL_ABI DirectHandleBase :
#ifdef DEBUG
public api_internal::StackAllocated<true>
#else
public api_internal::StackAllocated<false>
#endif
{
public:
V8_INLINE bool is_identical_to(const HandleBase& that) const;
V8_INLINE bool is_identical_to(const DirectHandleBase& that) const;
V8_INLINE bool is_null() const { return obj_ == kTaggedNullAddress; }
V8_INLINE Address address() const { return obj_; }
#ifdef DEBUG
V8_INLINE static int NumberOfHandles() { return number_of_handles_; }
class V8_NODISCARD ResetNumberOfHandlesScope {
public:
ResetNumberOfHandlesScope() : saved_number_of_handles_(number_of_handles_) {
number_of_handles_ = 0;
}
~ResetNumberOfHandlesScope() {
number_of_handles_ = saved_number_of_handles_;
}
private:
int saved_number_of_handles_;
};
#else
class V8_NODISCARD ResetNumberOfHandlesScope {};
#endif
protected:
friend class HandleBase;
#if defined(DEBUG) && V8_HAS_ATTRIBUTE_TRIVIAL_ABI
V8_INLINE DirectHandleBase(const DirectHandleBase& other) V8_NOEXCEPT
: obj_(other.obj_) {
Register();
}
DirectHandleBase& operator=(const DirectHandleBase&) V8_NOEXCEPT = default;
V8_INLINE ~DirectHandleBase() V8_NOEXCEPT { Unregister(); }
#endif
V8_INLINE explicit DirectHandleBase(Address object) : obj_(object) {
Register();
}
#ifdef DEBUG
V8_EXPORT_PRIVATE bool IsDereferenceAllowed() const;
#else
V8_INLINE bool IsDereferenceAllowed() const { return true; }
#endif
DirectHandleBase(Address obj, no_checking_tag do_not_check)
: StackAllocated(do_not_check), obj_(obj) {
Register();
}
Address obj_;
private:
V8_INLINE void Register() {
#if defined(DEBUG) && V8_HAS_ATTRIBUTE_TRIVIAL_ABI
++number_of_handles_;
#endif
}
V8_INLINE void Unregister() {
#if defined(DEBUG) && V8_HAS_ATTRIBUTE_TRIVIAL_ABI
DCHECK_LT(0, number_of_handles_);
--number_of_handles_;
#endif
}
#ifdef DEBUG
inline static thread_local int number_of_handles_ = 0;
#endif
};
template <typename T>
class DirectHandle : public DirectHandleBase {
public:
V8_INLINE DirectHandle() : DirectHandle(kTaggedNullAddress) {}
V8_INLINE explicit DirectHandle(Address object) : DirectHandleBase(object) {}
V8_INLINE DirectHandle(Tagged<T> object, Isolate* isolate)
: DirectHandle(object) {}
V8_INLINE DirectHandle(Tagged<T> object, LocalIsolate* isolate)
: DirectHandle(object) {}
V8_INLINE DirectHandle(Tagged<T> object, LocalHeap* local_heap)
: DirectHandle(object) {}
V8_INLINE explicit DirectHandle(Address* address)
: DirectHandle(address == nullptr ? kTaggedNullAddress : *address) {}
V8_INLINE static DirectHandle<T> New(Tagged<T> object, Isolate* isolate) {
return DirectHandle<T>(object);
}
template <typename S, typename = std::enable_if_t<is_subtype_v<S, T>>>
V8_INLINE DirectHandle(DirectHandle<S> handle) : DirectHandle(handle.obj_) {}
template <typename S, typename = std::enable_if_t<is_subtype_v<S, T>>>
V8_INLINE DirectHandle(Handle<S> handle)
: DirectHandle(handle.location() != nullptr ? *handle.location()
: kTaggedNullAddress) {}
V8_INLINE Tagged<T> operator->() const {
if constexpr (is_subtype_v<T, HeapObject>) {
return **this;
} else {
static_assert(
false,
"This handle does not reference a heap object. Use `(*handle).foo`.");
}
}
V8_INLINE Tagged<T> operator*() const {
static_assert(is_taggable_v<T>, "static type violation");
SLOW_DCHECK(IsDereferenceAllowed());
return Tagged<T>(address());
}
V8_INLINE static const DirectHandle<T> null() { return DirectHandle<T>(); }
bool equals(DirectHandle<T> other) const {
return address() == other.address();
}
void PatchValue(Tagged<T> new_value) {
SLOW_DCHECK(obj_ != kTaggedNullAddress && IsDereferenceAllowed());
obj_ = new_value.ptr();
}
private:
template <typename>
friend class DirectHandle;
template <typename>
friend class MaybeDirectHandle;
friend class DirectHandleUnchecked<T>;
template <typename To, typename From>
friend inline DirectHandle<To> Cast(DirectHandle<From> value,
const v8::SourceLocation& loc);
V8_INLINE explicit DirectHandle(Tagged<T> object);
explicit DirectHandle(no_checking_tag do_not_check)
: DirectHandleBase(kTaggedNullAddress, do_not_check) {}
explicit DirectHandle(const DirectHandle<T>& other,
no_checking_tag do_not_check)
: DirectHandleBase(other.obj_, do_not_check) {}
};
template <typename T>
std::ostream& operator<<(std::ostream& os, DirectHandle<T> handle);
template <typename T>
class V8_TRIVIAL_ABI DirectHandleUnchecked final : public DirectHandle<T> {
public:
DirectHandleUnchecked() : DirectHandle<T>(DirectHandle<T>::do_not_check) {}
#if defined(DEBUG) && V8_HAS_ATTRIBUTE_TRIVIAL_ABI
DirectHandleUnchecked(const DirectHandleUnchecked& other) V8_NOEXCEPT
: DirectHandle<T>(other, DirectHandle<T>::do_not_check) {}
DirectHandleUnchecked& operator=(const DirectHandleUnchecked&)
V8_NOEXCEPT = default;
#endif
DirectHandleUnchecked(const DirectHandle<T>& other)
V8_NOEXCEPT
: DirectHandle<T>(other, DirectHandle<T>::do_not_check) {}
};
template <typename T>
class StrongRootAllocator<DirectHandleUnchecked<T>>
: public StrongRootAllocatorBase {
public:
using value_type = DirectHandleUnchecked<T>;
static_assert(std::is_standard_layout_v<value_type>);
static_assert(sizeof(value_type) == sizeof(Address));
explicit StrongRootAllocator(Heap* heap) : StrongRootAllocatorBase(heap) {}
explicit StrongRootAllocator(Isolate* isolate)
: StrongRootAllocatorBase(isolate) {}
explicit StrongRootAllocator(v8::Isolate* isolate)
: StrongRootAllocatorBase(reinterpret_cast<Isolate*>(isolate)) {}
template <typename U>
StrongRootAllocator(const StrongRootAllocator<U>& other) noexcept
: StrongRootAllocatorBase(other) {}
value_type* allocate(size_t n) {
return reinterpret_cast<value_type*>(allocate_impl(n));
}
void deallocate(value_type* p, size_t n) noexcept {
return deallocate_impl(reinterpret_cast<Address*>(p), n);
}
};
template <typename T>
class DirectHandleVector {
private:
using element_type = internal::DirectHandleUnchecked<T>;
using allocator_type = internal::StrongRootAllocator<element_type>;
static allocator_type make_allocator(Isolate* isolate) noexcept {
return allocator_type(isolate);
}
using vector_type = std::vector<element_type, allocator_type>;
public:
using value_type = DirectHandle<T>;
using reference = value_type&;
using const_reference = const value_type&;
using size_type = size_t;
using difference_type = ptrdiff_t;
using iterator = internal::WrappedIterator<typename vector_type::iterator,
DirectHandle<T>>;
using const_iterator =
internal::WrappedIterator<typename vector_type::const_iterator,
const DirectHandle<T>>;
explicit DirectHandleVector(Isolate* isolate)
: backing_(make_allocator(isolate)) {}
DirectHandleVector(Isolate* isolate, size_t n)
: backing_(n, make_allocator(isolate)) {}
DirectHandleVector(Isolate* isolate,
std::initializer_list<DirectHandle<T>> init)
: backing_(make_allocator(isolate)) {
if (init.size() == 0) return;
backing_.reserve(init.size());
backing_.insert(backing_.end(), init.begin(), init.end());
}
iterator begin() noexcept { return iterator(backing_.begin()); }
const_iterator begin() const noexcept {
return const_iterator(backing_.begin());
}
iterator end() noexcept { return iterator(backing_.end()); }
const_iterator end() const noexcept { return const_iterator(backing_.end()); }
size_t size() const noexcept { return backing_.size(); }
bool empty() const noexcept { return backing_.empty(); }
void reserve(size_t n) { backing_.reserve(n); }
void shrink_to_fit() { backing_.shrink_to_fit(); }
DirectHandle<T>& operator[](size_t n) { return backing_[n]; }
const DirectHandle<T>& operator[](size_t n) const { return backing_[n]; }
DirectHandle<T>& at(size_t n) { return backing_.at(n); }
const DirectHandle<T>& at(size_t n) const { return backing_.at(n); }
DirectHandle<T>& front() { return backing_.front(); }
const DirectHandle<T>& front() const { return backing_.front(); }
DirectHandle<T>& back() { return backing_.back(); }
const DirectHandle<T>& back() const { return backing_.back(); }
DirectHandle<T>* data() noexcept { return backing_.data(); }
const DirectHandle<T>* data() const noexcept { return backing_.data(); }
iterator insert(const_iterator pos, const DirectHandle<T>& value) {
return iterator(backing_.insert(pos.base(), value));
}
template <typename InputIt>
iterator insert(const_iterator pos, InputIt first, InputIt last) {
return iterator(backing_.insert(pos.base(), first, last));
}
iterator insert(const_iterator pos,
std::initializer_list<DirectHandle<T>> init) {
return iterator(backing_.insert(pos.base(), init.begin(), init.end()));
}
DirectHandleVector<T>& operator=(
std::initializer_list<DirectHandle<T>> init) {
backing_.clear();
backing_.reserve(init.size());
backing_.insert(backing_.end(), init.begin(), init.end());
return *this;
}
void push_back(const DirectHandle<T>& x) { backing_.push_back(x); }
void pop_back() { backing_.pop_back(); }
void emplace_back(const DirectHandle<T>& x) { backing_.emplace_back(x); }
void clear() noexcept { backing_.clear(); }
void resize(size_t n) { backing_.resize(n); }
void swap(DirectHandleVector<T>& other) { backing_.swap(other.backing_); }
friend bool operator==(const DirectHandleVector<T>& x,
const DirectHandleVector<T>& y) {
return x.backing_ == y.backing_;
}
friend bool operator!=(const DirectHandleVector<T>& x,
const DirectHandleVector<T>& y) {
return x.backing_ != y.backing_;
}
friend bool operator<(const DirectHandleVector<T>& x,
const DirectHandleVector<T>& y) {
return x.backing_ < y.backing_;
}
friend bool operator>(const DirectHandleVector<T>& x,
const DirectHandleVector<T>& y) {
return x.backing_ > y.backing_;
}
friend bool operator<=(const DirectHandleVector<T>& x,
const DirectHandleVector<T>& y) {
return x.backing_ <= y.backing_;
}
friend bool operator>=(const DirectHandleVector<T>& x,
const DirectHandleVector<T>& y) {
return x.backing_ >= y.backing_;
}
private:
vector_type backing_;
};
#else
template <typename T>
class DirectHandleVector : public std::vector<DirectHandle<T>> { … };
#endif
}
}
#endif