1// Copyright 2023 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_HANDLE_BASE_H_
6#define INCLUDE_V8_HANDLE_BASE_H_
7
8#include "v8-internal.h"  // NOLINT(build/include_directory)
9
10namespace v8 {
11
12namespace internal {
13
14// Helper functions about values contained in handles.
15// A value is either an indirect pointer or a direct pointer, depending on
16// whether direct local support is enabled.
17class ValueHelper final {
18 public:
19#ifdef V8_ENABLE_DIRECT_LOCAL
20  static constexpr Address kTaggedNullAddress = 1;
21  static constexpr Address kEmpty = kTaggedNullAddress;
22#else
23  static constexpr Address kEmpty = kNullAddress;
24#endif  // V8_ENABLE_DIRECT_LOCAL
25
26  template <typename T>
27  V8_INLINE static bool IsEmpty(T* value) {
28    return reinterpret_cast<Address>(value) == kEmpty;
29  }
30
31  // Returns a handle's "value" for all kinds of abstract handles. For Local,
32  // it is equivalent to `*handle`. The variadic parameters support handle
33  // types with extra type parameters, like `Persistent<T, M>`.
34  template <template <typename T, typename... Ms> typename H, typename T,
35            typename... Ms>
36  V8_INLINE static T* HandleAsValue(const H<T, Ms...>& handle) {
37    return handle.template value<T>();
38  }
39
40#ifdef V8_ENABLE_DIRECT_LOCAL
41
42  template <typename T>
43  V8_INLINE static Address ValueAsAddress(const T* value) {
44    return reinterpret_cast<Address>(value);
45  }
46
47  template <typename T, typename S>
48  V8_INLINE static T* SlotAsValue(S* slot) {
49    return *reinterpret_cast<T**>(slot);
50  }
51
52  template <typename T>
53  V8_INLINE static T* ValueAsSlot(T* const& value) {
54    return reinterpret_cast<T*>(const_cast<T**>(&value));
55  }
56
57#else  // !V8_ENABLE_DIRECT_LOCAL
58
59  template <typename T>
60  V8_INLINE static Address ValueAsAddress(const T* value) {
61    return *reinterpret_cast<const Address*>(value);
62  }
63
64  template <typename T, typename S>
65  V8_INLINE static T* SlotAsValue(S* slot) {
66    return reinterpret_cast<T*>(slot);
67  }
68
69  template <typename T>
70  V8_INLINE static T* ValueAsSlot(T* const& value) {
71    return value;
72  }
73
74#endif  // V8_ENABLE_DIRECT_LOCAL
75};
76
77/**
78 * Helper functions about handles.
79 */
80class HandleHelper final {
81 public:
82  /**
83   * Checks whether two handles are equal.
84   * They are equal iff they are both empty or they are both non-empty and the
85   * objects to which they refer are physically equal.
86   *
87   * If both handles refer to JS objects, this is the same as strict equality.
88   * For primitives, such as numbers or strings, a `false` return value does not
89   * indicate that the values aren't equal in the JavaScript sense.
90   * Use `Value::StrictEquals()` to check primitives for equality.
91   */
92  template <typename T1, typename T2>
93  V8_INLINE static bool EqualHandles(const T1& lhs, const T2& rhs) {
94    if (lhs.IsEmpty()) return rhs.IsEmpty();
95    if (rhs.IsEmpty()) return false;
96    return lhs.ptr() == rhs.ptr();
97  }
98};
99
100}  // namespace internal
101
102/**
103 * A base class for abstract handles containing indirect pointers.
104 * These are useful regardless of whether direct local support is enabled.
105 */
106class IndirectHandleBase {
107 public:
108  // Returns true if the handle is empty.
109  V8_INLINE bool IsEmpty() const { return location_ == nullptr; }
110
111  // Sets the handle to be empty. IsEmpty() will then return true.
112  V8_INLINE void Clear() { location_ = nullptr; }
113
114 protected:
115  friend class internal::ValueHelper;
116  friend class internal::HandleHelper;
117
118  V8_INLINE IndirectHandleBase() = default;
119  V8_INLINE IndirectHandleBase(const IndirectHandleBase& other) = default;
120  V8_INLINE IndirectHandleBase& operator=(const IndirectHandleBase& that) =
121      default;
122
123  V8_INLINE explicit IndirectHandleBase(internal::Address* location)
124      : location_(location) {}
125
126  // Returns the address of the actual heap object (tagged).
127  // This method must be called only if the handle is not empty, otherwise it
128  // will crash.
129  V8_INLINE internal::Address ptr() const { return *location_; }
130
131  // Returns a reference to the slot (indirect pointer).
132  V8_INLINE internal::Address* const& slot() const { return location_; }
133  V8_INLINE internal::Address*& slot() { return location_; }
134
135  // Returns the handler's "value" (direct or indirect pointer, depending on
136  // whether direct local support is enabled).
137  template <typename T>
138  V8_INLINE T* value() const {
139    return internal::ValueHelper::SlotAsValue<T>(slot());
140  }
141
142 private:
143  internal::Address* location_ = nullptr;
144};
145
146#ifdef V8_ENABLE_DIRECT_LOCAL
147
148/**
149 * A base class for abstract handles containing direct pointers.
150 * These are only possible when conservative stack scanning is enabled.
151 */
152class DirectHandleBase {
153 public:
154  // Returns true if the handle is empty.
155  V8_INLINE bool IsEmpty() const {
156    return ptr_ == internal::ValueHelper::kEmpty;
157  }
158
159  // Sets the handle to be empty. IsEmpty() will then return true.
160  V8_INLINE void Clear() { ptr_ = internal::ValueHelper::kEmpty; }
161
162 protected:
163  friend class internal::ValueHelper;
164  friend class internal::HandleHelper;
165
166  V8_INLINE DirectHandleBase() = default;
167  V8_INLINE DirectHandleBase(const DirectHandleBase& other) = default;
168  V8_INLINE DirectHandleBase& operator=(const DirectHandleBase& that) = default;
169
170  V8_INLINE explicit DirectHandleBase(internal::Address ptr) : ptr_(ptr) {}
171
172  // Returns the address of the referenced object.
173  V8_INLINE internal::Address ptr() const { return ptr_; }
174
175  // Returns the handler's "value" (direct pointer, as direct local support
176  // is guaranteed to be enabled here).
177  template <typename T>
178  V8_INLINE T* value() const {
179    return reinterpret_cast<T*>(ptr_);
180  }
181
182 private:
183  internal::Address ptr_ = internal::ValueHelper::kEmpty;
184};
185
186#endif  // V8_ENABLE_DIRECT_LOCAL
187
188}  // namespace v8
189
190#endif  // INCLUDE_V8_HANDLE_BASE_H_
191