| 1 | // Copyright 2011 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 V8_MAYBE_HANDLES_H_ |
| 6 | #define V8_MAYBE_HANDLES_H_ |
| 7 | |
| 8 | #include <type_traits> |
| 9 | |
| 10 | #include "src/handles.h" |
| 11 | |
| 12 | namespace v8 { |
| 13 | namespace internal { |
| 14 | |
| 15 | // ---------------------------------------------------------------------------- |
| 16 | // A Handle can be converted into a MaybeHandle. Converting a MaybeHandle |
| 17 | // into a Handle requires checking that it does not point to nullptr. This |
| 18 | // ensures nullptr checks before use. |
| 19 | // |
| 20 | // Also note that Handles do not provide default equality comparison or hashing |
| 21 | // operators on purpose. Such operators would be misleading, because intended |
| 22 | // semantics is ambiguous between Handle location and object identity. |
| 23 | template <typename T> |
| 24 | class MaybeHandle final { |
| 25 | public: |
| 26 | V8_INLINE MaybeHandle() = default; |
| 27 | |
| 28 | // Constructor for handling automatic up casting from Handle. |
| 29 | // Ex. Handle<JSArray> can be passed when MaybeHandle<Object> is expected. |
| 30 | template <typename S, typename = typename std::enable_if< |
| 31 | std::is_convertible<S*, T*>::value>::type> |
| 32 | V8_INLINE MaybeHandle(Handle<S> handle) : location_(handle.location_) {} |
| 33 | |
| 34 | // Constructor for handling automatic up casting. |
| 35 | // Ex. MaybeHandle<JSArray> can be passed when Handle<Object> is expected. |
| 36 | template <typename S, typename = typename std::enable_if< |
| 37 | std::is_convertible<S*, T*>::value>::type> |
| 38 | V8_INLINE MaybeHandle(MaybeHandle<S> maybe_handle) |
| 39 | : location_(maybe_handle.location_) {} |
| 40 | |
| 41 | V8_INLINE MaybeHandle(T object, Isolate* isolate); |
| 42 | |
| 43 | V8_INLINE void Assert() const { DCHECK_NOT_NULL(location_); } |
| 44 | V8_INLINE void Check() const { CHECK_NOT_NULL(location_); } |
| 45 | |
| 46 | V8_INLINE Handle<T> ToHandleChecked() const { |
| 47 | Check(); |
| 48 | return Handle<T>(location_); |
| 49 | } |
| 50 | |
| 51 | // Convert to a Handle with a type that can be upcasted to. |
| 52 | template <typename S> |
| 53 | V8_INLINE bool ToHandle(Handle<S>* out) const { |
| 54 | if (location_ == nullptr) { |
| 55 | *out = Handle<T>::null(); |
| 56 | return false; |
| 57 | } else { |
| 58 | *out = Handle<T>(location_); |
| 59 | return true; |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | // Returns the raw address where this handle is stored. This should only be |
| 64 | // used for hashing handles; do not ever try to dereference it. |
| 65 | V8_INLINE Address address() const { |
| 66 | return reinterpret_cast<Address>(location_); |
| 67 | } |
| 68 | |
| 69 | bool is_null() const { return location_ == nullptr; } |
| 70 | |
| 71 | protected: |
| 72 | Address* location_ = nullptr; |
| 73 | |
| 74 | // MaybeHandles of different classes are allowed to access each |
| 75 | // other's location_. |
| 76 | template <typename> |
| 77 | friend class MaybeHandle; |
| 78 | }; |
| 79 | |
| 80 | // A handle which contains a potentially weak pointer. Keeps it alive (strongly) |
| 81 | // while the MaybeObjectHandle is alive. |
| 82 | class MaybeObjectHandle { |
| 83 | public: |
| 84 | inline MaybeObjectHandle(); |
| 85 | inline MaybeObjectHandle(MaybeObject object, Isolate* isolate); |
| 86 | inline MaybeObjectHandle(Object object, Isolate* isolate); |
| 87 | inline explicit MaybeObjectHandle(Handle<Object> object); |
| 88 | |
| 89 | static inline MaybeObjectHandle Weak(Object object, Isolate* isolate); |
| 90 | static inline MaybeObjectHandle Weak(Handle<Object> object); |
| 91 | |
| 92 | inline MaybeObject operator*() const; |
| 93 | inline MaybeObject operator->() const; |
| 94 | inline Handle<Object> object() const; |
| 95 | |
| 96 | bool is_identical_to(const MaybeObjectHandle& other) const { |
| 97 | Handle<Object> this_handle; |
| 98 | Handle<Object> other_handle; |
| 99 | return reference_type_ == other.reference_type_ && |
| 100 | handle_.ToHandle(&this_handle) == |
| 101 | other.handle_.ToHandle(&other_handle) && |
| 102 | this_handle.is_identical_to(other_handle); |
| 103 | } |
| 104 | |
| 105 | bool is_null() const { return handle_.is_null(); } |
| 106 | |
| 107 | private: |
| 108 | inline MaybeObjectHandle(Object object, |
| 109 | HeapObjectReferenceType reference_type, |
| 110 | Isolate* isolate); |
| 111 | inline MaybeObjectHandle(Handle<Object> object, |
| 112 | HeapObjectReferenceType reference_type); |
| 113 | |
| 114 | HeapObjectReferenceType reference_type_; |
| 115 | MaybeHandle<Object> handle_; |
| 116 | }; |
| 117 | |
| 118 | } // namespace internal |
| 119 | } // namespace v8 |
| 120 | |
| 121 | #endif // V8_MAYBE_HANDLES_H_ |
| 122 | |