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