• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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