• 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_JS_HCLASS_INL_H
17 #define ECMASCRIPT_JS_HCLASS_INL_H
18 
19 #include "ecmascript/js_hclass.h"
20 
21 #include "ecmascript/layout_info-inl.h"
22 #include "ecmascript/byte_array.h"
23 #include "ecmascript/mem/assert_scope.h"
24 #include "ecmascript/transitions_dictionary.h"
25 
26 namespace panda::ecmascript {
Cast(const TaggedObject * object)27 inline JSHClass *JSHClass::Cast(const TaggedObject *object)
28 {
29     ASSERT(JSTaggedValue(object).IsJSHClass());
30     return static_cast<JSHClass *>(const_cast<TaggedObject *>(object));
31 }
32 
AddTransitions(const JSThread * thread,const JSHandle<JSHClass> & parent,const JSHandle<JSHClass> & child,const JSHandle<JSTaggedValue> & key,PropertyAttributes attributes)33 void JSHClass::AddTransitions(const JSThread *thread, const JSHandle<JSHClass> &parent, const JSHandle<JSHClass> &child,
34                               const JSHandle<JSTaggedValue> &key, PropertyAttributes attributes)
35 {
36     UpdateRootHClass(thread, parent, child);
37     JSTaggedValue transitions = parent->GetTransitions();
38     if (transitions.IsUndefined()) {
39         JSTaggedValue weakChild = JSTaggedValue(child.GetTaggedValue().CreateAndGetWeakRef());
40         parent->SetTransitions(thread, weakChild);
41         return;
42     }
43     JSMutableHandle<TransitionsDictionary> dict(thread, JSTaggedValue::Undefined());
44     if (transitions.IsWeak()) {
45         auto cachedHClass = JSHClass::Cast(transitions.GetTaggedWeakRef());
46         uint32_t last = cachedHClass->NumberOfProps() - 1;
47         LayoutInfo *layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout().GetTaggedObject());
48         auto attr = JSHandle<JSTaggedValue>(thread, JSTaggedValue(layoutInfo->GetAttr(last).GetPropertyMetaData()));
49         auto lastKey = JSHandle<JSTaggedValue>(thread, layoutInfo->GetKey(last));
50         auto lastHClass = JSHandle<JSTaggedValue>(thread, cachedHClass);
51         dict.Update(TransitionsDictionary::Create(thread));
52         transitions = TransitionsDictionary::PutIfAbsent(thread, dict, lastKey, lastHClass, attr).GetTaggedValue();
53     }
54     auto attr = JSHandle<JSTaggedValue>(thread, JSTaggedValue(attributes.GetPropertyMetaData()));
55     dict.Update(transitions);
56     transitions =
57         TransitionsDictionary::PutIfAbsent(thread, dict, key, JSHandle<JSTaggedValue>(child), attr).GetTaggedValue();
58     parent->SetTransitions(thread, transitions);
59 }
60 
AddExtensionTransitions(const JSThread * thread,const JSHandle<JSHClass> & parent,const JSHandle<JSHClass> & child,const JSHandle<JSTaggedValue> & key)61 void JSHClass::AddExtensionTransitions(const JSThread *thread, const JSHandle<JSHClass> &parent,
62                                        const JSHandle<JSHClass> &child, const JSHandle<JSTaggedValue> &key)
63 {
64     auto attr = JSHandle<JSTaggedValue>(thread, PropertyAttributes(0).GetTaggedValue());
65     AddProtoTransitions(thread, parent, child, key, attr);
66 }
67 
AddProtoTransitions(const JSThread * thread,const JSHandle<JSHClass> & parent,const JSHandle<JSHClass> & child,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & proto)68 void JSHClass::AddProtoTransitions(const JSThread *thread, const JSHandle<JSHClass> &parent,
69                                    const JSHandle<JSHClass> &child, const JSHandle<JSTaggedValue> &key,
70                                    const JSHandle<JSTaggedValue> &proto)
71 {
72     UpdateRootHClass(thread, parent, child);
73     JSTaggedValue transitions = parent->GetTransitions();
74     JSMutableHandle<TransitionsDictionary> dict(thread, JSTaggedValue::Undefined());
75     if (transitions.IsUndefined()) {
76         transitions = TransitionsDictionary::Create(thread).GetTaggedValue();
77     } else if (transitions.IsWeak()) {
78         auto cachedHClass = JSHClass::Cast(transitions.GetTaggedWeakRef());
79         uint32_t last = cachedHClass->NumberOfProps() - 1;
80         LayoutInfo *layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout().GetTaggedObject());
81         auto attr = JSHandle<JSTaggedValue>(thread, JSTaggedValue(layoutInfo->GetAttr(last).GetPropertyMetaData()));
82         auto lastKey = JSHandle<JSTaggedValue>(thread, layoutInfo->GetKey(last));
83         auto lastHClass = JSHandle<JSTaggedValue>(thread, cachedHClass);
84         dict.Update(TransitionsDictionary::Create(thread));
85         transitions = TransitionsDictionary::PutIfAbsent(thread, dict, lastKey, lastHClass, attr).GetTaggedValue();
86     }
87 
88     dict.Update(transitions);
89     transitions =
90         TransitionsDictionary::PutIfAbsent(thread, dict, key, JSHandle<JSTaggedValue>(child), proto).GetTaggedValue();
91     parent->SetTransitions(thread, transitions);
92 }
93 
FindTransitions(const JSTaggedValue & key,const JSTaggedValue & attributes)94 inline JSHClass *JSHClass::FindTransitions(const JSTaggedValue &key, const JSTaggedValue &attributes)
95 {
96     DISALLOW_GARBAGE_COLLECTION;
97     JSTaggedValue transitions = GetTransitions();
98     if (transitions.IsUndefined()) {
99         return nullptr;
100     }
101     if (transitions.IsWeak()) {
102         auto cachedHClass = JSHClass::Cast(transitions.GetTaggedWeakRef());
103         int last = static_cast<int>(cachedHClass->NumberOfProps()) - 1;
104         LayoutInfo *layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout().GetTaggedObject());
105         auto attr = layoutInfo->GetAttr(last).GetPropertyMetaData();
106         auto cachedKey = layoutInfo->GetKey(last);
107         if (attr == attributes.GetInt() && key == cachedKey) {
108             return cachedHClass;
109         }
110         return nullptr;
111     }
112 
113     ASSERT(transitions.IsTaggedArray());
114     TransitionsDictionary *dict = TransitionsDictionary::Cast(transitions.GetTaggedObject());
115     auto entry = dict->FindEntry(key, attributes);
116     if (entry == -1) {
117         return nullptr;
118     }
119 
120     JSTaggedValue ret = dict->GetValue(entry);
121     if (ret.IsUndefined()) {
122         return nullptr;
123     }
124 
125     return JSHClass::Cast(ret.GetTaggedWeakRef());
126 }
127 
FindProtoTransitions(const JSTaggedValue & key,const JSTaggedValue & proto)128 inline JSHClass *JSHClass::FindProtoTransitions(const JSTaggedValue &key, const JSTaggedValue &proto)
129 {
130     DISALLOW_GARBAGE_COLLECTION;
131     JSTaggedValue transitions = GetTransitions();
132     if (transitions.IsWeak() || !transitions.IsTaggedArray()) {
133         ASSERT(transitions.IsUndefined() || transitions.IsWeak());
134         return nullptr;
135     }
136     ASSERT(transitions.IsTaggedArray());
137     TransitionsDictionary *dict = TransitionsDictionary::Cast(transitions.GetTaggedObject());
138     auto entry = dict->FindEntry(key, proto);
139     if (entry == -1) {
140         return nullptr;
141     }
142 
143     JSTaggedValue ret = dict->GetValue(entry);
144     if (ret.IsUndefined()) {
145         return nullptr;
146     }
147 
148     return JSHClass::Cast(ret.GetTaggedWeakRef());
149 }
150 
UpdatePropertyMetaData(const JSThread * thread,const JSTaggedValue & key,const PropertyAttributes & metaData)151 inline void JSHClass::UpdatePropertyMetaData(const JSThread *thread, [[maybe_unused]] const JSTaggedValue &key,
152                                              const PropertyAttributes &metaData)
153 {
154     DISALLOW_GARBAGE_COLLECTION;
155     ASSERT(!GetLayout().IsNull());
156     LayoutInfo *layoutInfo = LayoutInfo::Cast(GetLayout().GetTaggedObject());
157     ASSERT(layoutInfo->GetLength() != 0);
158     uint32_t entry = metaData.GetOffset();
159 
160     layoutInfo->SetNormalAttr(thread, entry, metaData);
161 }
162 
HasReferenceField()163 inline bool JSHClass::HasReferenceField()
164 {
165     auto type = GetObjectType();
166     switch (type) {
167         case JSType::LINE_STRING:
168         case JSType::CONSTANT_STRING:
169         case JSType::JS_NATIVE_POINTER:
170             return false;
171         default:
172             return true;
173     }
174 }
175 
SizeFromJSHClass(TaggedObject * header)176 inline size_t JSHClass::SizeFromJSHClass(TaggedObject *header)
177 {
178     // CAUTION! Never use T::Cast(header) in this function
179     // it would cause issue during GC because hclass may forward to a new addres
180     // and the casting method would still use the old address.
181     auto type = GetObjectType();
182     size_t size = 0;
183     switch (type) {
184         case JSType::TAGGED_ARRAY:
185         case JSType::TAGGED_DICTIONARY:
186         case JSType::LEXICAL_ENV:
187         case JSType::CONSTANT_POOL:
188         case JSType::AOT_LITERAL_INFO:
189         case JSType::VTABLE:
190         case JSType::COW_TAGGED_ARRAY:
191         case JSType::MUTANT_TAGGED_ARRAY:
192         case JSType::COW_MUTANT_TAGGED_ARRAY:
193         case JSType::PROFILE_TYPE_INFO:
194             size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(),
195                 reinterpret_cast<TaggedArray *>(header)->GetLength());
196             break;
197         case JSType::BYTE_ARRAY:
198             size = ByteArray::ComputeSize(reinterpret_cast<ByteArray *>(header)->GetByteLength(),
199                                           reinterpret_cast<ByteArray *>(header)->GetArrayLength());
200             size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
201             break;
202         case JSType::LINE_STRING:
203             size = LineEcmaString::ObjectSize(reinterpret_cast<EcmaString* >(header));
204             size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
205             break;
206         case JSType::CONSTANT_STRING:
207             size = ConstantString::SIZE;
208             size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
209             break;
210         case JSType::TREE_STRING:
211             size = TreeEcmaString::SIZE;
212             size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
213             break;
214         case JSType::SLICED_STRING:
215             size = SlicedString::SIZE;
216             size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
217             break;
218         case JSType::MACHINE_CODE_OBJECT:
219             size = reinterpret_cast<MachineCode *>(header)->GetMachineCodeObjectSize();
220             size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
221             break;
222         case JSType::BIGINT:
223             size = BigInt::ComputeSize(reinterpret_cast<BigInt *>(header)->GetLength());
224             size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
225             break;
226         default:
227             ASSERT(GetObjectSize() != 0);
228             size = GetObjectSize();
229             break;
230     }
231     ASSERT(AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)) == size);
232     return size;
233 }
234 
Copy(const JSThread * thread,const JSHClass * jshclass)235 inline void JSHClass::Copy(const JSThread *thread, const JSHClass *jshclass)
236 {
237     DISALLOW_GARBAGE_COLLECTION;
238 
239     // copy jshclass
240     SetPrototype(thread, jshclass->GetPrototype());
241     SetBitField(jshclass->GetBitField());
242     SetIsAllTaggedProp(jshclass->IsAllTaggedProp());
243     SetNumberOfProps(jshclass->NumberOfProps());
244 }
245 
FindRootHClass(JSHClass * hclass)246 inline JSHClass *JSHClass::FindRootHClass(JSHClass *hclass)
247 {
248     auto root = hclass;
249     auto parent = hclass->GetParent();
250     while (parent.IsJSHClass()) {
251         root = JSHClass::Cast(parent.GetTaggedObject());
252         parent = root->GetParent();
253     }
254     return root;
255 }
256 
FindProtoHClass(JSHClass * hclass)257 inline JSTaggedValue JSHClass::FindProtoHClass(JSHClass *hclass)
258 {
259     auto proto = hclass->GetProto();
260     if (proto.IsJSObject()) {
261         auto prototypeObj = JSObject::Cast(proto);
262         return JSTaggedValue(prototypeObj->GetClass());
263     }
264     return JSTaggedValue::Undefined();
265 }
266 
FindProtoRootHClass(JSHClass * hclass)267 inline JSTaggedValue JSHClass::FindProtoRootHClass(JSHClass *hclass)
268 {
269     auto proto = hclass->GetProto();
270     if (proto.IsJSObject()) {
271         auto prototypeObj = JSObject::Cast(proto);
272         auto prototypeHClass = prototypeObj->GetClass();
273         return JSTaggedValue(JSHClass::FindRootHClass(prototypeHClass));
274     }
275     return JSTaggedValue::Undefined();
276 }
277 
UpdateRootHClass(const JSThread * thread,const JSHandle<JSHClass> & parent,const JSHandle<JSHClass> & child)278 inline void JSHClass::UpdateRootHClass(const JSThread *thread, const JSHandle<JSHClass> &parent,
279                                        const JSHandle<JSHClass> &child)
280 {
281     if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
282         child->SetParent(thread, parent);
283     }
284 }
285 
FindPropertyEntry(const JSThread * thread,JSHClass * hclass,JSTaggedValue key)286 inline int JSHClass::FindPropertyEntry(const JSThread *thread, JSHClass *hclass, JSTaggedValue key)
287 {
288     DISALLOW_GARBAGE_COLLECTION;
289     LayoutInfo *layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
290     uint32_t propsNumber = hclass->NumberOfProps();
291     int entry = layout->FindElementWithCache(thread, hclass, key, propsNumber);
292     return entry;
293 }
294 
295 template<bool checkDuplicateKeys /* = false*/>
AddPropertyToNewHClass(const JSThread * thread,JSHandle<JSHClass> & jshclass,JSHandle<JSHClass> & newJsHClass,const JSHandle<JSTaggedValue> & key,const PropertyAttributes & attr)296 void JSHClass::AddPropertyToNewHClass(const JSThread *thread, JSHandle<JSHClass> &jshclass,
297                                       JSHandle<JSHClass> &newJsHClass,
298                                       const JSHandle<JSTaggedValue> &key,
299                                       const PropertyAttributes &attr)
300 {
301     ASSERT(!jshclass->IsDictionaryMode());
302     ASSERT(!newJsHClass->IsDictionaryMode());
303     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
304     // Add Property and metaData
305     uint32_t offset = attr.GetOffset();
306     newJsHClass->IncNumberOfProps();
307 
308     {
309         JSMutableHandle<LayoutInfo> layoutInfoHandle(thread, newJsHClass->GetLayout());
310 
311         if (layoutInfoHandle->NumberOfElements() != static_cast<int>(offset)) {
312             layoutInfoHandle.Update(factory->CopyAndReSort(layoutInfoHandle, offset, offset + 1));
313         } else if (layoutInfoHandle->GetPropertiesCapacity() <= static_cast<int>(offset)) {  // need to Grow
314             layoutInfoHandle.Update(
315                 factory->ExtendLayoutInfo(layoutInfoHandle, offset));
316         }
317         newJsHClass->SetLayout(thread, layoutInfoHandle);
318         layoutInfoHandle->AddKey<checkDuplicateKeys>(thread, offset, key.GetTaggedValue(), attr);
319     }
320 
321     // Add newClass to old hclass's transitions.
322     AddTransitions(thread, jshclass, newJsHClass, key, attr);
323 }
324 
325 template<bool checkDuplicateKeys /* = false*/>
SetPropertyOfObjHClass(const JSThread * thread,JSHandle<JSHClass> & jshclass,const JSHandle<JSTaggedValue> & key,const PropertyAttributes & attr)326 JSHandle<JSHClass> JSHClass::SetPropertyOfObjHClass(const JSThread *thread, JSHandle<JSHClass> &jshclass,
327                                                     const JSHandle<JSTaggedValue> &key,
328                                                     const PropertyAttributes &attr)
329 {
330     JSHClass *newClass = jshclass->FindTransitions(key.GetTaggedValue(), JSTaggedValue(attr.GetPropertyMetaData()));
331     if (newClass != nullptr) {
332         newClass->SetPrototype(thread, jshclass->GetPrototype());
333         return JSHandle<JSHClass>(thread, newClass);
334     }
335 
336     JSHandle<JSHClass> newJsHClass = JSHClass::Clone(thread, jshclass);
337     AddPropertyToNewHClass<checkDuplicateKeys>(thread, jshclass, newJsHClass, key, attr);
338     return newJsHClass;
339 }
340 }  // namespace panda::ecmascript
341 
342 #endif  // ECMASCRIPT_JS_HCLASS_INL_H
343