1 /* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef ECMASCRIPT_JSHANDLE_H 17 #define ECMASCRIPT_JSHANDLE_H 18 19 #include <type_traits> 20 21 #include "ecmascript/ecma_handle_scope.h" 22 #include "ecmascript/js_tagged_value.h" 23 24 /* 25 * JSHandle: A JSHandle provides a reference to an object that survives relocation by the garbage collector. 26 * 27 * HandleStorage: Handles are only valid within a HandleScope. When a JSHandle is created for an object a cell is 28 * allocated in the current HandleScope. 29 * 30 * HandleStorage: HandleStorage is the storage structure of the object pointer. GC will use the stored pointer as root 31 * and update the stored value after the object is moved 32 * 33 * JSHandle ---- HandleStorage ----- heap 34 * | | | 35 * address-----> store: T* ------> object 36 * 37 * { 38 * EcmaHandleScope scope2(thread); 39 * JSHandle<T> jhandle(thread, obj4); 40 * JSHandle<T> jhandle(thread, obj5); 41 * JSHandle<T> jhandle(thread, obj6); 42 * JSHandle<T> jhandle(thread, obj7); 43 * } 44 * 45 * // out of scope, The obj pointer in node will be free (obj7, obj6, obj5, obj4) and PopTopNode(top_node = prev_node) 46 * 47 * | | | obj5 | 48 * | | scope2-> | obj4 | 49 * | | | obj3 | 50 * | obj7 | | obj2 | 51 * |__obj6__| scope1-> |__obj1___| 52 * top_node ---------> prev_node------>nullptr 53 * 54 * example: 55 * JSHandle<T> handle; 56 * { 57 * EcmaHandleScope(thread); 58 * JSHandle<T> jshandle(thread, T*); 59 * jshandle->method(); // to invoke method of T 60 * handle = jshandle; 61 * } 62 * handle->method(); // error! do not used handle out of scope 63 */ 64 65 namespace panda::test { 66 class JSHandleTest; 67 } // namespace panda::test 68 69 namespace panda::ecmascript { 70 class TaggedArray; 71 class LinkedHashMap; 72 class LinkedHashSet; 73 class NameDictionary; 74 75 template <typename T> 76 class JSHandle { 77 public: JSHandle()78 inline JSHandle() : address_(reinterpret_cast<uintptr_t>(nullptr)) {} 79 ~JSHandle() = default; 80 DEFAULT_NOEXCEPT_MOVE_SEMANTIC(JSHandle); 81 DEFAULT_COPY_SEMANTIC(JSHandle); 82 JSHandle(const JSThread * thread,JSTaggedValue value)83 JSHandle(const JSThread *thread, JSTaggedValue value) 84 { 85 address_ = EcmaHandleScope::NewHandle(const_cast<JSThread *>(thread), value.GetRawData()); 86 } 87 JSHandle(const JSThread * thread,const TaggedObject * value)88 JSHandle(const JSThread *thread, const TaggedObject *value) 89 { 90 address_ = EcmaHandleScope::NewHandle(const_cast<JSThread *>(thread), JSTaggedValue(value).GetRawData()); 91 } 92 GetAddress()93 inline uintptr_t GetAddress() const 94 { 95 return address_; 96 } 97 98 template <typename S> JSHandle(const JSHandle<S> & handle)99 explicit JSHandle(const JSHandle<S> &handle) : address_(handle.GetAddress()) {} 100 101 template <typename S> Cast(const JSHandle<S> & handle)102 inline static JSHandle<T> Cast(const JSHandle<S> &handle) 103 { 104 T::Cast(handle.GetTaggedValue().GetTaggedObject()); 105 return JSHandle<T>(handle.GetAddress()); 106 } 107 GetTaggedValue()108 inline JSTaggedValue GetTaggedValue() const 109 { 110 if (GetAddress() == 0U) { 111 return JSTaggedValue::Undefined(); 112 } 113 return *(reinterpret_cast<JSTaggedValue *>(GetAddress())); // NOLINT(clang-analyzer-core.NullDereference) 114 } 115 GetTaggedType()116 inline JSTaggedType GetTaggedType() const 117 { 118 if (GetAddress() == 0U) { 119 return JSTaggedValue::Undefined().GetRawData(); 120 } 121 return *reinterpret_cast<JSTaggedType *>(GetAddress()); // NOLINT(clang-analyzer-core.NullDereference) 122 } 123 124 inline T *operator*() const 125 { 126 return T::Cast(GetTaggedValue().GetTaggedObject()); 127 } 128 129 inline T *operator->() const 130 { 131 return T::Cast(GetTaggedValue().GetTaggedObject()); 132 } 133 134 inline bool operator==(const JSHandle<T> &other) const 135 { 136 return GetTaggedType() == other.GetTaggedType(); 137 } 138 139 inline bool operator!=(const JSHandle<T> &other) const 140 { 141 return GetTaggedType() != other.GetTaggedType(); 142 } 143 IsEmpty()144 inline bool IsEmpty() const 145 { 146 return GetAddress() == 0U; 147 } 148 149 template <typename R> GetObject()150 R *GetObject() const 151 { 152 return reinterpret_cast<R *>(GetTaggedValue().GetTaggedObject()); 153 } 154 JSHandle(uintptr_t slot)155 inline explicit JSHandle(uintptr_t slot) : address_(slot) 156 { 157 if (!std::is_convertible<T *, JSTaggedValue *>::value) { 158 ASSERT(slot != 0); 159 if ((*reinterpret_cast<JSTaggedValue *>(slot)).IsHeapObject()) { 160 T::Cast((*reinterpret_cast<JSTaggedValue *>(slot)).GetTaggedObject()); 161 } 162 } 163 } 164 Dump()165 void Dump() const DUMP_API_ATTR 166 { 167 GetTaggedValue().D(); 168 } 169 170 private: JSHandle(const JSTaggedType * slot)171 inline explicit JSHandle(const JSTaggedType *slot) : address_(reinterpret_cast<uintptr_t>(slot)) {} JSHandle(const T * const * slot)172 inline explicit JSHandle(const T *const *slot) : address_(reinterpret_cast<uintptr_t>(slot)) {} 173 174 uintptr_t address_; // NOLINT(misc-non-private-member-variables-in-classes) 175 friend class EcmaVM; 176 friend class GlobalEnv; 177 friend class JSHandleTest; 178 friend class GlobalHandleCollection; 179 friend class RuntimeStubs; 180 }; 181 182 template <> 183 inline JSTaggedValue *JSHandle<JSTaggedValue>::operator->() const 184 { 185 return reinterpret_cast<JSTaggedValue *>(GetAddress()); 186 } 187 188 template <> 189 inline JSTaggedValue *JSHandle<JSTaggedValue>::operator*() const 190 { 191 return reinterpret_cast<JSTaggedValue *>(GetAddress()); 192 } 193 194 template <typename T> 195 class JSMutableHandle : public JSHandle<T> { 196 public: 197 JSMutableHandle() = default; 198 ~JSMutableHandle() = default; 199 DEFAULT_NOEXCEPT_MOVE_SEMANTIC(JSMutableHandle); 200 DEFAULT_COPY_SEMANTIC(JSMutableHandle); 201 JSMutableHandle(const JSThread * thread,JSTaggedValue value)202 JSMutableHandle(const JSThread *thread, JSTaggedValue value) : JSHandle<T>(thread, value) {} JSMutableHandle(const JSThread * thread,const TaggedArray * value)203 JSMutableHandle(const JSThread *thread, const TaggedArray *value) : JSHandle<T>(thread, value) {} 204 template <typename S> JSMutableHandle(const JSThread * thread,const JSHandle<S> & handle)205 JSMutableHandle(const JSThread *thread, const JSHandle<S> &handle) 206 : JSHandle<T>(thread, handle.GetTaggedValue()) 207 { 208 } JSMutableHandle(uintptr_t slot)209 inline explicit JSMutableHandle(uintptr_t slot) : JSHandle<T>(slot) 210 { 211 } 212 213 template <typename S> Cast(const JSMutableHandle<S> & handle)214 inline static JSMutableHandle<T> Cast(const JSMutableHandle<S> &handle) 215 { 216 JSHandle<T>::Cast(handle); 217 return JSMutableHandle<T>(handle.GetAddress()); 218 } 219 Update(JSTaggedValue value)220 void Update(JSTaggedValue value) 221 { 222 auto addr = reinterpret_cast<JSTaggedValue *>(this->GetAddress()); 223 ASSERT(addr != nullptr); 224 *addr = value; 225 } 226 227 template <typename S> Update(const JSHandle<S> & handle)228 void Update(const JSHandle<S> &handle) 229 { 230 auto addr = reinterpret_cast<JSTaggedValue *>(this->GetAddress()); 231 *addr = handle.GetTaggedValue(); 232 } 233 }; 234 } // namespace panda::ecmascript 235 236 #endif // ECMASCRIPT_JSHANDLE_H 237