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 #include "ecmascript/mem/assert_scope.h" 24 25 /* 26 * JSHandle: A JSHandle provides a reference to an object that survives relocation by the garbage collector. 27 * 28 * HandleStorage: Handles are only valid within a HandleScope. When a JSHandle is created for an object a cell is 29 * allocated in the current HandleScope. 30 * 31 * HandleStorage: HandleStorage is the storage structure of the object pointer. GC will use the stored pointer as root 32 * and update the stored value after the object is moved 33 * 34 * JSHandle ---- HandleStorage ----- heap 35 * | | | 36 * address-----> store: T* ------> object 37 * 38 * { 39 * EcmaHandleScope scope2(thread); 40 * JSHandle<T> jhandle(thread, obj4); 41 * JSHandle<T> jhandle(thread, obj5); 42 * JSHandle<T> jhandle(thread, obj6); 43 * JSHandle<T> jhandle(thread, obj7); 44 * } 45 * 46 * // out of scope, The obj pointer in node will be free (obj7, obj6, obj5, obj4) and PopTopNode(top_node = prev_node) 47 * 48 * | | | obj5 | 49 * | | scope2-> | obj4 | 50 * | | | obj3 | 51 * | obj7 | | obj2 | 52 * |__obj6__| scope1-> |__obj1___| 53 * top_node ---------> prev_node------>nullptr 54 * 55 * example: 56 * JSHandle<T> handle; 57 * { 58 * EcmaHandleScope(thread); 59 * JSHandle<T> jshandle(thread, T*); 60 * jshandle->method(); // to invoke method of T 61 * handle = jshandle; 62 * } 63 * handle->method(); // error! do not used handle out of scope 64 */ 65 66 namespace panda::test { 67 class JSHandleTest; 68 } // namespace panda::test 69 70 namespace panda::ecmascript { 71 class TaggedArray; 72 class LinkedHashMap; 73 class LinkedHashSet; 74 class NameDictionary; 75 76 template <typename T> 77 class JSHandle { 78 public: JSHandle()79 inline JSHandle() : address_(reinterpret_cast<uintptr_t>(nullptr)) {} 80 ~JSHandle() = default; 81 DEFAULT_NOEXCEPT_MOVE_SEMANTIC(JSHandle); 82 DEFAULT_COPY_SEMANTIC(JSHandle); 83 JSHandle(const JSThread * thread,JSTaggedValue value)84 JSHandle(const JSThread *thread, JSTaggedValue value) 85 { 86 address_ = EcmaHandleScope::NewHandle(const_cast<JSThread *>(thread), value.GetRawData()); 87 } 88 JSHandle(const JSThread * thread,JSTaggedValue value,bool isPrimitive)89 JSHandle(const JSThread *thread, JSTaggedValue value, bool isPrimitive) 90 { 91 if (LIKELY(isPrimitive)) { 92 address_ = EcmaHandleScope::NewPrimitiveHandle( 93 const_cast<JSThread *>(thread), value.GetRawData()); 94 return; 95 } 96 address_ = EcmaHandleScope::NewHandle(const_cast<JSThread *>(thread), value.GetRawData()); 97 } 98 JSHandle(const JSThread * thread,const TaggedObject * value)99 JSHandle(const JSThread *thread, const TaggedObject *value) 100 { 101 address_ = EcmaHandleScope::NewHandle(const_cast<JSThread *>(thread), JSTaggedValue(value).GetRawData()); 102 } 103 GetAddress()104 inline uintptr_t GetAddress() const 105 { 106 return address_; 107 } 108 109 template <typename S> JSHandle(const JSHandle<S> & handle)110 explicit JSHandle(const JSHandle<S> &handle) : address_(handle.GetAddress()) {} 111 112 template <typename S> Cast(const JSHandle<S> & handle)113 inline static JSHandle<T> Cast(const JSHandle<S> &handle) 114 { 115 T::Cast(handle.GetTaggedValue().GetTaggedObject()); 116 return JSHandle<T>(handle.GetAddress()); 117 } 118 GetTaggedValue()119 inline JSTaggedValue GetTaggedValue() const 120 { 121 CHECK_NO_DEREF_HANDLE; 122 if (GetAddress() == 0U) { 123 return JSTaggedValue::Undefined(); 124 } 125 return *(reinterpret_cast<JSTaggedValue *>(GetAddress())); // NOLINT(clang-analyzer-core.NullDereference) 126 } 127 GetTaggedType()128 inline JSTaggedType GetTaggedType() const 129 { 130 CHECK_NO_DEREF_HANDLE; 131 if (GetAddress() == 0U) { 132 return JSTaggedValue::Undefined().GetRawData(); 133 } 134 return *reinterpret_cast<JSTaggedType *>(GetAddress()); // NOLINT(clang-analyzer-core.NullDereference) 135 } 136 137 inline T *operator*() const 138 { 139 return T::Cast(GetTaggedValue().GetTaggedObject()); 140 } 141 142 inline T *operator->() const 143 { 144 return T::Cast(GetTaggedValue().GetTaggedObject()); 145 } 146 147 inline bool operator==(const JSHandle<T> &other) const 148 { 149 return GetTaggedType() == other.GetTaggedType(); 150 } 151 152 inline bool operator!=(const JSHandle<T> &other) const 153 { 154 return GetTaggedType() != other.GetTaggedType(); 155 } 156 IsEmpty()157 inline bool IsEmpty() const 158 { 159 return GetAddress() == 0U; 160 } 161 162 template <typename R> GetObject()163 R *GetObject() const 164 { 165 return reinterpret_cast<R *>(GetTaggedValue().GetTaggedObject()); 166 } 167 JSHandle(uintptr_t slot)168 inline explicit JSHandle(uintptr_t slot) : address_(slot) 169 { 170 if (!std::is_convertible<T *, JSTaggedValue *>::value) { 171 ASSERT(slot != 0); 172 if ((*reinterpret_cast<JSTaggedValue *>(slot)).IsHeapObject()) { 173 T::Cast((*reinterpret_cast<JSTaggedValue *>(slot)).GetTaggedObject()); 174 } 175 } 176 } 177 Dump()178 void Dump() const DUMP_API_ATTR 179 { 180 GetTaggedValue().D(); 181 } 182 183 private: JSHandle(const JSTaggedType * slot)184 inline explicit JSHandle(const JSTaggedType *slot) : address_(reinterpret_cast<uintptr_t>(slot)) {} JSHandle(const T * const * slot)185 inline explicit JSHandle(const T *const *slot) : address_(reinterpret_cast<uintptr_t>(slot)) {} 186 187 uintptr_t address_; // NOLINT(misc-non-private-member-variables-in-classes) 188 friend class EcmaVM; 189 friend class GlobalEnv; 190 friend class JSHandleTest; 191 friend class GlobalHandleCollection; 192 friend class RuntimeStubs; 193 }; 194 195 template <> 196 inline JSTaggedValue *JSHandle<JSTaggedValue>::operator->() const 197 { 198 return reinterpret_cast<JSTaggedValue *>(GetAddress()); 199 } 200 201 template <> 202 inline JSTaggedValue *JSHandle<JSTaggedValue>::operator*() const 203 { 204 return reinterpret_cast<JSTaggedValue *>(GetAddress()); 205 } 206 207 template <typename T> 208 class JSMutableHandle : public JSHandle<T> { 209 public: 210 JSMutableHandle() = default; 211 ~JSMutableHandle() = default; 212 DEFAULT_NOEXCEPT_MOVE_SEMANTIC(JSMutableHandle); 213 DEFAULT_COPY_SEMANTIC(JSMutableHandle); 214 JSMutableHandle(const JSThread * thread,JSTaggedValue value)215 JSMutableHandle(const JSThread *thread, JSTaggedValue value) : JSHandle<T>(thread, value) {} JSMutableHandle(const JSThread * thread,const TaggedArray * value)216 JSMutableHandle(const JSThread *thread, const TaggedArray *value) : JSHandle<T>(thread, value) {} 217 template <typename S> JSMutableHandle(const JSThread * thread,const JSHandle<S> & handle)218 JSMutableHandle(const JSThread *thread, const JSHandle<S> &handle) 219 : JSHandle<T>(thread, handle.GetTaggedValue()) 220 { 221 } JSMutableHandle(uintptr_t slot)222 inline explicit JSMutableHandle(uintptr_t slot) : JSHandle<T>(slot) 223 { 224 } 225 226 template <typename S> Cast(const JSMutableHandle<S> & handle)227 inline static JSMutableHandle<T> Cast(const JSMutableHandle<S> &handle) 228 { 229 JSHandle<T>::Cast(handle); 230 return JSMutableHandle<T>(handle.GetAddress()); 231 } 232 Update(JSTaggedValue value)233 void Update(JSTaggedValue value) 234 { 235 auto addr = reinterpret_cast<JSTaggedValue *>(this->GetAddress()); 236 ASSERT(addr != nullptr); 237 *addr = value; 238 } 239 240 template <typename S> Update(const JSHandle<S> & handle)241 void Update(const JSHandle<S> &handle) 242 { 243 auto addr = reinterpret_cast<JSTaggedValue *>(this->GetAddress()); 244 *addr = handle.GetTaggedValue(); 245 } 246 }; 247 248 template<typename> 249 struct IsJSHandle : std::false_type {}; 250 251 template<typename Value> 252 struct IsJSHandle<JSHandle<Value>> : std::true_type {}; 253 254 template<typename Value> 255 struct IsJSHandle<JSMutableHandle<Value>> : std::true_type {}; 256 } // namespace panda::ecmascript 257 258 #endif // ECMASCRIPT_JSHANDLE_H 259