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 JSTaggedValue transitions = parent->GetTransitions();
37 if (transitions.IsUndefined()) {
38 JSTaggedValue weakChild = JSTaggedValue(child.GetTaggedValue().CreateAndGetWeakRef());
39 parent->SetTransitions(thread, weakChild);
40 return;
41 }
42 JSMutableHandle<TransitionsDictionary> dict(thread, JSTaggedValue::Undefined());
43 if (transitions.IsWeak()) {
44 auto cachedHClass = JSHClass::Cast(transitions.GetTaggedWeakRef());
45 uint32_t last = cachedHClass->NumberOfProps() - 1;
46 LayoutInfo *layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout().GetTaggedObject());
47 auto attr = JSHandle<JSTaggedValue>(thread, JSTaggedValue(layoutInfo->GetAttr(last).GetPropertyMetaData()));
48 auto lastKey = JSHandle<JSTaggedValue>(thread, layoutInfo->GetKey(last));
49 auto lastHClass = JSHandle<JSTaggedValue>(thread, cachedHClass);
50 dict.Update(TransitionsDictionary::Create(thread));
51 transitions = TransitionsDictionary::PutIfAbsent(thread, dict, lastKey, lastHClass, attr).GetTaggedValue();
52 }
53 auto attr = JSHandle<JSTaggedValue>(thread, JSTaggedValue(attributes.GetPropertyMetaData()));
54 dict.Update(transitions);
55 transitions =
56 TransitionsDictionary::PutIfAbsent(thread, dict, key, JSHandle<JSTaggedValue>(child), attr).GetTaggedValue();
57 parent->SetTransitions(thread, transitions);
58 }
59
AddExtensionTransitions(const JSThread * thread,const JSHandle<JSHClass> & parent,const JSHandle<JSHClass> & child,const JSHandle<JSTaggedValue> & key)60 void JSHClass::AddExtensionTransitions(const JSThread *thread, const JSHandle<JSHClass> &parent,
61 const JSHandle<JSHClass> &child, const JSHandle<JSTaggedValue> &key)
62 {
63 auto attr = JSHandle<JSTaggedValue>(thread, PropertyAttributes(0).GetTaggedValue());
64 AddProtoTransitions(thread, parent, child, key, attr);
65 }
66
AddProtoTransitions(const JSThread * thread,const JSHandle<JSHClass> & parent,const JSHandle<JSHClass> & child,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & proto)67 void JSHClass::AddProtoTransitions(const JSThread *thread, const JSHandle<JSHClass> &parent,
68 const JSHandle<JSHClass> &child, const JSHandle<JSTaggedValue> &key,
69 const JSHandle<JSTaggedValue> &proto)
70 {
71 JSTaggedValue transitions = parent->GetTransitions();
72 JSMutableHandle<TransitionsDictionary> dict(thread, JSTaggedValue::Undefined());
73 if (transitions.IsUndefined()) {
74 transitions = TransitionsDictionary::Create(thread).GetTaggedValue();
75 } else if (transitions.IsWeak()) {
76 auto cachedHClass = JSHClass::Cast(transitions.GetTaggedWeakRef());
77 uint32_t last = cachedHClass->NumberOfProps() - 1;
78 LayoutInfo *layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout().GetTaggedObject());
79 auto attr = JSHandle<JSTaggedValue>(thread, JSTaggedValue(layoutInfo->GetAttr(last).GetPropertyMetaData()));
80 auto lastKey = JSHandle<JSTaggedValue>(thread, layoutInfo->GetKey(last));
81 auto lastHClass = JSHandle<JSTaggedValue>(thread, cachedHClass);
82 dict.Update(TransitionsDictionary::Create(thread));
83 transitions = TransitionsDictionary::PutIfAbsent(thread, dict, lastKey, lastHClass, attr).GetTaggedValue();
84 }
85
86 dict.Update(transitions);
87 transitions =
88 TransitionsDictionary::PutIfAbsent(thread, dict, key, JSHandle<JSTaggedValue>(child), proto).GetTaggedValue();
89 parent->SetTransitions(thread, transitions);
90 }
91
FindTransitions(const JSTaggedValue & key,const JSTaggedValue & attributes)92 inline JSHClass *JSHClass::FindTransitions(const JSTaggedValue &key, const JSTaggedValue &attributes)
93 {
94 DISALLOW_GARBAGE_COLLECTION;
95 JSTaggedValue transitions = GetTransitions();
96 if (transitions.IsUndefined()) {
97 return nullptr;
98 }
99 if (transitions.IsWeak()) {
100 auto cachedHClass = JSHClass::Cast(transitions.GetTaggedWeakRef());
101 int last = static_cast<int>(cachedHClass->NumberOfProps()) - 1;
102 LayoutInfo *layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout().GetTaggedObject());
103 auto attr = layoutInfo->GetAttr(last).GetPropertyMetaData();
104 auto cachedKey = layoutInfo->GetKey(last);
105 if (attr == attributes.GetInt() && key == cachedKey) {
106 return cachedHClass;
107 }
108 return nullptr;
109 }
110
111 ASSERT(transitions.IsTaggedArray());
112 TransitionsDictionary *dict = TransitionsDictionary::Cast(transitions.GetTaggedObject());
113 auto entry = dict->FindEntry(key, attributes);
114 if (entry == -1) {
115 return nullptr;
116 }
117
118 JSTaggedValue ret = dict->GetValue(entry);
119 if (ret.IsUndefined()) {
120 return nullptr;
121 }
122
123 return JSHClass::Cast(ret.GetTaggedWeakRef());
124 }
125
FindProtoTransitions(const JSTaggedValue & key,const JSTaggedValue & proto)126 inline JSHClass *JSHClass::FindProtoTransitions(const JSTaggedValue &key, const JSTaggedValue &proto)
127 {
128 DISALLOW_GARBAGE_COLLECTION;
129 JSTaggedValue transitions = GetTransitions();
130 if (transitions.IsWeak() || !transitions.IsTaggedArray()) {
131 ASSERT(transitions.IsUndefined() || transitions.IsWeak());
132 return nullptr;
133 }
134 ASSERT(transitions.IsTaggedArray());
135 TransitionsDictionary *dict = TransitionsDictionary::Cast(transitions.GetTaggedObject());
136 auto entry = dict->FindEntry(key, proto);
137 if (entry == -1) {
138 return nullptr;
139 }
140
141 JSTaggedValue ret = dict->GetValue(entry);
142 if (ret.IsUndefined()) {
143 return nullptr;
144 }
145
146 return JSHClass::Cast(ret.GetTaggedWeakRef());
147 }
148
UpdatePropertyMetaData(const JSThread * thread,const JSTaggedValue & key,const PropertyAttributes & metaData)149 inline void JSHClass::UpdatePropertyMetaData(const JSThread *thread, [[maybe_unused]] const JSTaggedValue &key,
150 const PropertyAttributes &metaData)
151 {
152 DISALLOW_GARBAGE_COLLECTION;
153 ASSERT(!GetLayout().IsNull());
154 LayoutInfo *layoutInfo = LayoutInfo::Cast(GetLayout().GetTaggedObject());
155 ASSERT(layoutInfo->GetLength() != 0);
156 uint32_t entry = metaData.GetOffset();
157
158 layoutInfo->SetNormalAttr(thread, entry, metaData);
159 }
160
HasReferenceField()161 inline bool JSHClass::HasReferenceField()
162 {
163 auto type = GetObjectType();
164 switch (type) {
165 case JSType::LINE_STRING:
166 case JSType::CONSTANT_STRING:
167 case JSType::JS_NATIVE_POINTER:
168 return false;
169 default:
170 return true;
171 }
172 }
173
SizeFromJSHClass(TaggedObject * header)174 inline size_t JSHClass::SizeFromJSHClass(TaggedObject *header)
175 {
176 // CAUTION! Never use T::Cast(header) in this function
177 // it would cause issue during GC because hclass may forward to a new addres
178 // and the casting method would still use the old address.
179 auto type = GetObjectType();
180 size_t size = 0;
181 switch (type) {
182 case JSType::TAGGED_ARRAY:
183 case JSType::TAGGED_DICTIONARY:
184 case JSType::LEXICAL_ENV:
185 case JSType::CONSTANT_POOL:
186 case JSType::AOT_LITERAL_INFO:
187 case JSType::VTABLE:
188 case JSType::COW_TAGGED_ARRAY:
189 size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(),
190 reinterpret_cast<TaggedArray *>(header)->GetLength());
191 break;
192 case JSType::BYTE_ARRAY:
193 size = ByteArray::ComputeSize(reinterpret_cast<ByteArray *>(header)->GetByteLength(),
194 reinterpret_cast<ByteArray *>(header)->GetArrayLength());
195 size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
196 break;
197 case JSType::LINE_STRING:
198 size = LineEcmaString::ObjectSize(reinterpret_cast<EcmaString* >(header));
199 size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
200 break;
201 case JSType::CONSTANT_STRING:
202 size = ConstantString::SIZE;
203 size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
204 break;
205 case JSType::TREE_STRING:
206 size = TreeEcmaString::SIZE;
207 size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
208 break;
209 case JSType::MACHINE_CODE_OBJECT:
210 size = reinterpret_cast<MachineCode *>(header)->GetMachineCodeObjectSize();
211 size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
212 break;
213 case JSType::BIGINT:
214 size = BigInt::ComputeSize(reinterpret_cast<BigInt *>(header)->GetLength());
215 size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
216 break;
217 default:
218 ASSERT(GetObjectSize() != 0);
219 size = GetObjectSize();
220 break;
221 }
222 ASSERT(AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)) == size);
223 return size;
224 }
225
Copy(const JSThread * thread,const JSHClass * jshclass)226 inline void JSHClass::Copy(const JSThread *thread, const JSHClass *jshclass)
227 {
228 DISALLOW_GARBAGE_COLLECTION;
229
230 // copy jshclass
231 SetPrototype(thread, jshclass->GetPrototype());
232 SetBitField(jshclass->GetBitField());
233 SetIsAllTaggedProp(jshclass->IsAllTaggedProp());
234 SetNumberOfProps(jshclass->NumberOfProps());
235 }
236
FindPropertyEntry(const JSThread * thread,JSHClass * hclass,JSTaggedValue key)237 inline int JSHClass::FindPropertyEntry(const JSThread *thread, JSHClass *hclass, JSTaggedValue key)
238 {
239 DISALLOW_GARBAGE_COLLECTION;
240 LayoutInfo *layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
241 uint32_t propsNumber = hclass->NumberOfProps();
242 int entry = layout->FindElementWithCache(thread, hclass, key, propsNumber);
243 return entry;
244 }
245 } // namespace panda::ecmascript
246
247 #endif // ECMASCRIPT_JS_HCLASS_INL_H
248