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::STRING:
166 case JSType::JS_NATIVE_POINTER:
167 return false;
168 default:
169 return true;
170 }
171 }
172
SizeFromJSHClass(TaggedObject * header)173 inline size_t JSHClass::SizeFromJSHClass(TaggedObject *header)
174 {
175 // CAUTION! Never use T::Cast(header) in this function
176 // it would cause issue during GC because hclass may forward to a new addres
177 // and the casting method would still use the old address.
178 auto type = GetObjectType();
179 size_t size = 0;
180 switch (type) {
181 case JSType::TAGGED_ARRAY:
182 case JSType::TAGGED_DICTIONARY:
183 case JSType::LEXICAL_ENV:
184 case JSType::CONSTANT_POOL:
185 case JSType::AOT_LITERAL_INFO:
186 case JSType::COW_TAGGED_ARRAY:
187 size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(),
188 reinterpret_cast<TaggedArray *>(header)->GetLength());
189 break;
190 case JSType::BYTE_ARRAY:
191 size = ByteArray::ComputeSize(reinterpret_cast<ByteArray *>(header)->GetSize(),
192 reinterpret_cast<ByteArray *>(header)->GetLength());
193 size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
194 break;
195 case JSType::STRING:
196 size = EcmaStringAccessor(reinterpret_cast<EcmaString *>(header)).ObjectSize();
197 size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
198 break;
199 case JSType::MACHINE_CODE_OBJECT:
200 size = reinterpret_cast<MachineCode *>(header)->GetMachineCodeObjectSize();
201 size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
202 break;
203 case JSType::BIGINT:
204 size = BigInt::ComputeSize(reinterpret_cast<BigInt *>(header)->GetLength());
205 size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
206 break;
207 default:
208 ASSERT(GetObjectSize() != 0);
209 size = GetObjectSize();
210 break;
211 }
212 ASSERT(AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)) == size);
213 return size;
214 }
215
Copy(const JSThread * thread,const JSHClass * jshclass)216 inline void JSHClass::Copy(const JSThread *thread, const JSHClass *jshclass)
217 {
218 DISALLOW_GARBAGE_COLLECTION;
219
220 // copy jshclass
221 SetPrototype(thread, jshclass->GetPrototype());
222 SetBitField(jshclass->GetBitField());
223 SetNumberOfProps(jshclass->NumberOfProps());
224 }
225 } // namespace panda::ecmascript
226
227 #endif // ECMASCRIPT_JS_HCLASS_INL_H
228