• 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 
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             T::Cast((*reinterpret_cast<JSTaggedValue *>(slot)).GetTaggedObject());
160         }
161     }
162 
Dump()163     void Dump() const DUMP_API_ATTR
164     {
165         GetTaggedValue().D();
166     }
167 
168 private:
JSHandle(const JSTaggedType * slot)169     inline explicit JSHandle(const JSTaggedType *slot) : address_(reinterpret_cast<uintptr_t>(slot)) {}
JSHandle(const T * const * slot)170     inline explicit JSHandle(const T *const *slot) : address_(reinterpret_cast<uintptr_t>(slot)) {}
171 
172     uintptr_t address_;  // NOLINT(misc-non-private-member-variables-in-classes)
173     friend class EcmaVM;
174     friend class GlobalEnv;
175     friend class JSHandleTest;
176     friend class GlobalHandleCollection;
177     friend class RuntimeStubs;
178 };
179 
180 template <>
181 inline JSTaggedValue *JSHandle<JSTaggedValue>::operator->() const
182 {
183     return reinterpret_cast<JSTaggedValue *>(GetAddress());
184 }
185 
186 template <>
187 inline JSTaggedValue *JSHandle<JSTaggedValue>::operator*() const
188 {
189     return reinterpret_cast<JSTaggedValue *>(GetAddress());
190 }
191 
192 template <typename T>
193 class JSMutableHandle : public JSHandle<T> {
194 public:
195     JSMutableHandle() = default;
196     ~JSMutableHandle() = default;
197     DEFAULT_NOEXCEPT_MOVE_SEMANTIC(JSMutableHandle);
198     DEFAULT_COPY_SEMANTIC(JSMutableHandle);
199 
JSMutableHandle(const JSThread * thread,JSTaggedValue value)200     JSMutableHandle(const JSThread *thread, JSTaggedValue value) : JSHandle<T>(thread, value) {}
JSMutableHandle(const JSThread * thread,const TaggedArray * value)201     JSMutableHandle(const JSThread *thread, const TaggedArray *value) : JSHandle<T>(thread, value) {}
202     template <typename S>
JSMutableHandle(const JSThread * thread,const JSHandle<S> & handle)203     JSMutableHandle(const JSThread *thread, const JSHandle<S> &handle)
204         : JSHandle<T>(thread, handle.GetTaggedValue())
205     {
206     }
JSMutableHandle(uintptr_t slot)207     inline explicit JSMutableHandle(uintptr_t slot) : JSHandle<T>(slot)
208     {
209     }
210 
211     template <typename S>
Cast(const JSMutableHandle<S> & handle)212     inline static JSMutableHandle<T> Cast(const JSMutableHandle<S> &handle)
213     {
214         JSHandle<T>::Cast(handle);
215         return JSMutableHandle<T>(handle.GetAddress());
216     }
217 
Update(JSTaggedValue value)218     void Update(JSTaggedValue value)
219     {
220         auto addr = reinterpret_cast<JSTaggedValue *>(this->GetAddress());
221         ASSERT(addr != nullptr);
222         *addr = value;
223     }
224 
225     template <typename S>
Update(const JSHandle<S> & handle)226     void Update(const JSHandle<S> &handle)
227     {
228         auto addr = reinterpret_cast<JSTaggedValue *>(this->GetAddress());
229         *addr = handle.GetTaggedValue();
230     }
231 };
232 }  // namespace panda::ecmascript
233 
234 #endif  // ECMASCRIPT_JSHANDLE_H
235