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 10 namespace v8 { 11 12 namespace 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. 17 class 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> IsEmpty(T* value)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> HandleAsValue(const H<T, Ms...>& handle)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> ValueAsAddress(const T* value)43 V8_INLINE static Address ValueAsAddress(const T* value) { 44 return reinterpret_cast<Address>(value); 45 } 46 47 template <typename T, typename S> SlotAsValue(S* slot)48 V8_INLINE static T* SlotAsValue(S* slot) { 49 return *reinterpret_cast<T**>(slot); 50 } 51 52 template <typename T> ValueAsSlot(T* const& value)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> ValueAsAddress(const T* value)60 V8_INLINE static Address ValueAsAddress(const T* value) { 61 return *reinterpret_cast<const Address*>(value); 62 } 63 64 template <typename T, typename S> SlotAsValue(S* slot)65 V8_INLINE static T* SlotAsValue(S* slot) { 66 return reinterpret_cast<T*>(slot); 67 } 68 69 template <typename T> ValueAsSlot(T* const& value)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 */ 80 class 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> EqualHandles(const T1& lhs, const T2& rhs)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 */ 106 class IndirectHandleBase { 107 public: 108 // Returns true if the handle is empty. IsEmpty() const109 V8_INLINE bool IsEmpty() const { return location_ == nullptr; } 110 111 // Sets the handle to be empty. IsEmpty() will then return true. Clear()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 IndirectHandleBase(internal::Address* location)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. ptr() const129 V8_INLINE internal::Address ptr() const { return *location_; } 130 131 // Returns a reference to the slot (indirect pointer). slot() const132 V8_INLINE internal::Address* const& slot() const { return location_; } slot()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> value() const138 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 */ 152 class DirectHandleBase { 153 public: 154 // Returns true if the handle is empty. IsEmpty() const155 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. Clear()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 DirectHandleBase(internal::Address ptr)170 V8_INLINE explicit DirectHandleBase(internal::Address ptr) : ptr_(ptr) {} 171 172 // Returns the address of the referenced object. ptr() const173 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> value() const178 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