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/transitions_dictionary.h"
23 #include "ecmascript/mem/assert_scope.h"
24
25 namespace panda::ecmascript {
Cast(const TaggedObject * object)26 inline JSHClass *JSHClass::Cast(const TaggedObject *object)
27 {
28 ASSERT(JSTaggedValue(object).IsJSHClass());
29 return static_cast<JSHClass *>(const_cast<TaggedObject *>(object));
30 }
31
AddTransitions(const JSThread * thread,const JSHandle<JSHClass> & parent,const JSHandle<JSHClass> & child,const JSHandle<JSTaggedValue> & key,PropertyAttributes attributes)32 void JSHClass::AddTransitions(const JSThread *thread, const JSHandle<JSHClass> &parent, const JSHandle<JSHClass> &child,
33 const JSHandle<JSTaggedValue> &key, PropertyAttributes attributes)
34 {
35 JSTaggedValue transitions = parent->GetTransitions();
36 if (transitions.IsUndefined()) {
37 JSTaggedValue weakChild = JSTaggedValue(child.GetTaggedValue().CreateAndGetWeakRef());
38 parent->SetTransitions(thread, weakChild);
39 return;
40 }
41 JSMutableHandle<TransitionsDictionary> dict(thread, JSTaggedValue::Undefined());
42 if (transitions.IsWeak()) {
43 auto cachedHClass = JSHClass::Cast(transitions.GetTaggedWeakRef());
44 int last = cachedHClass->NumberOfProps() - 1;
45 LayoutInfo *layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout().GetTaggedObject());
46 auto attr = JSHandle<JSTaggedValue>(thread, JSTaggedValue(layoutInfo->GetAttr(last).GetPropertyMetaData()));
47 auto lastKey = JSHandle<JSTaggedValue>(thread, layoutInfo->GetKey(last));
48 auto lastHClass = JSHandle<JSTaggedValue>(thread, cachedHClass);
49 dict.Update(TransitionsDictionary::Create(thread));
50 transitions = TransitionsDictionary::PutIfAbsent(thread, dict, lastKey, lastHClass, attr).GetTaggedValue();
51 }
52 auto attr = JSHandle<JSTaggedValue>(thread, JSTaggedValue(attributes.GetPropertyMetaData()));
53 dict.Update(transitions);
54 transitions =
55 TransitionsDictionary::PutIfAbsent(thread, dict, key, JSHandle<JSTaggedValue>(child), attr).GetTaggedValue();
56 parent->SetTransitions(thread, transitions);
57 }
58
AddExtensionTransitions(const JSThread * thread,const JSHandle<JSHClass> & parent,const JSHandle<JSHClass> & child,const JSHandle<JSTaggedValue> & key)59 void JSHClass::AddExtensionTransitions(const JSThread *thread, const JSHandle<JSHClass> &parent,
60 const JSHandle<JSHClass> &child, const JSHandle<JSTaggedValue> &key)
61 {
62 auto attr = JSHandle<JSTaggedValue>(thread, PropertyAttributes(0).GetTaggedValue());
63 AddProtoTransitions(thread, parent, child, key, attr);
64 }
65
AddProtoTransitions(const JSThread * thread,const JSHandle<JSHClass> & parent,const JSHandle<JSHClass> & child,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & proto)66 void JSHClass::AddProtoTransitions(const JSThread *thread, const JSHandle<JSHClass> &parent,
67 const JSHandle<JSHClass> &child, const JSHandle<JSTaggedValue> &key,
68 const JSHandle<JSTaggedValue> &proto)
69 {
70 JSTaggedValue transitions = parent->GetTransitions();
71 JSMutableHandle<TransitionsDictionary> dict(thread, JSTaggedValue::Undefined());
72 if (transitions.IsUndefined()) {
73 transitions = TransitionsDictionary::Create(thread).GetTaggedValue();
74 } else if (transitions.IsWeak()) {
75 auto cachedHClass = JSHClass::Cast(transitions.GetTaggedWeakRef());
76 int last = cachedHClass->NumberOfProps() - 1;
77 LayoutInfo *layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout().GetTaggedObject());
78 auto attr = JSHandle<JSTaggedValue>(thread, JSTaggedValue(layoutInfo->GetAttr(last).GetPropertyMetaData()));
79 auto lastKey = JSHandle<JSTaggedValue>(thread, layoutInfo->GetKey(last));
80 auto lastHClass = JSHandle<JSTaggedValue>(thread, cachedHClass);
81 dict.Update(TransitionsDictionary::Create(thread));
82 transitions = TransitionsDictionary::PutIfAbsent(thread, dict, lastKey, lastHClass, attr).GetTaggedValue();
83 }
84
85 dict.Update(transitions);
86 transitions =
87 TransitionsDictionary::PutIfAbsent(thread, dict, key, JSHandle<JSTaggedValue>(child), proto).GetTaggedValue();
88 parent->SetTransitions(thread, transitions);
89 }
90
FindTransitions(const JSTaggedValue & key,const JSTaggedValue & attributes)91 inline JSHClass *JSHClass::FindTransitions(const JSTaggedValue &key, const JSTaggedValue &attributes)
92 {
93 DISALLOW_GARBAGE_COLLECTION;
94 JSTaggedValue transitions = GetTransitions();
95 if (transitions.IsUndefined()) {
96 return nullptr;
97 }
98 if (transitions.IsWeak()) {
99 auto cachedHClass = JSHClass::Cast(transitions.GetTaggedWeakRef());
100 int last = cachedHClass->NumberOfProps() - 1;
101 LayoutInfo *layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout().GetTaggedObject());
102 auto attr = layoutInfo->GetAttr(last).GetPropertyMetaData();
103 auto cachedKey = layoutInfo->GetKey(last);
104 if (attr == attributes.GetInt() && key == cachedKey) {
105 return cachedHClass;
106 }
107 return nullptr;
108 }
109
110 ASSERT(transitions.IsTaggedArray());
111 TransitionsDictionary *dict = TransitionsDictionary::Cast(transitions.GetTaggedObject());
112 auto entry = dict->FindEntry(key, attributes);
113 if (entry == -1) {
114 return nullptr;
115 }
116
117 JSTaggedValue ret = dict->GetValue(entry);
118 if (ret.IsUndefined()) {
119 return nullptr;
120 }
121
122 return JSHClass::Cast(ret.GetTaggedWeakRef());
123 }
124
FindProtoTransitions(const JSTaggedValue & key,const JSTaggedValue & proto)125 inline JSHClass *JSHClass::FindProtoTransitions(const JSTaggedValue &key, const JSTaggedValue &proto)
126 {
127 DISALLOW_GARBAGE_COLLECTION;
128 JSTaggedValue transitions = GetTransitions();
129 if (transitions.IsWeak() || !transitions.IsTaggedArray()) {
130 ASSERT(transitions.IsUndefined() || transitions.IsWeak());
131 return nullptr;
132 }
133 ASSERT(transitions.IsTaggedArray());
134 TransitionsDictionary *dict = TransitionsDictionary::Cast(transitions.GetTaggedObject());
135 auto entry = dict->FindEntry(key, proto);
136 if (entry == -1) {
137 return nullptr;
138 }
139
140 JSTaggedValue ret = dict->GetValue(entry);
141 if (ret.IsUndefined()) {
142 return nullptr;
143 }
144
145 return JSHClass::Cast(ret.GetTaggedWeakRef());
146 }
147
UpdatePropertyMetaData(const JSThread * thread,const JSTaggedValue & key,const PropertyAttributes & metaData)148 inline void JSHClass::UpdatePropertyMetaData(const JSThread *thread, [[maybe_unused]] const JSTaggedValue &key,
149 const PropertyAttributes &metaData)
150 {
151 DISALLOW_GARBAGE_COLLECTION;
152 ASSERT(!GetLayout().IsNull());
153 LayoutInfo *layoutInfo = LayoutInfo::Cast(GetLayout().GetTaggedObject());
154 ASSERT(layoutInfo->GetLength() != 0);
155 int entry = metaData.GetOffset();
156
157 layoutInfo->SetNormalAttr(thread, entry, metaData);
158 }
159
HasReferenceField()160 inline bool JSHClass::HasReferenceField()
161 {
162 auto type = GetObjectType();
163 switch (type) {
164 case JSType::STRING:
165 case JSType::JS_NATIVE_POINTER:
166 return false;
167 default:
168 return true;
169 }
170 }
171
SizeFromJSHClass(TaggedObject * header)172 inline size_t JSHClass::SizeFromJSHClass(TaggedObject *header)
173 {
174 auto type = GetObjectType();
175 size_t size = 0;
176 switch (type) {
177 case JSType::TAGGED_ARRAY:
178 case JSType::TAGGED_DICTIONARY:
179 size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(),
180 reinterpret_cast<TaggedArray *>(header)->GetLength());
181 break;
182 case JSType::STRING:
183 size = reinterpret_cast<EcmaString *>(header)->ObjectSize();
184 size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
185 break;
186 case JSType::MACHINE_CODE_OBJECT:
187 size = reinterpret_cast<MachineCode *>(header)->GetMachineCodeObjectSize();
188 size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
189 break;
190 default:
191 ASSERT(GetObjectSize() != 0);
192 size = GetObjectSize();
193 break;
194 }
195 ASSERT(AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)) == size);
196 return size;
197 }
198
Copy(const JSThread * thread,const JSHClass * jshcalss)199 inline void JSHClass::Copy(const JSThread *thread, const JSHClass *jshcalss)
200 {
201 DISALLOW_GARBAGE_COLLECTION;
202
203 // copy jshclass
204 SetPrototype(thread, jshcalss->GetPrototype());
205 SetBitField(jshcalss->GetBitField());
206 SetNumberOfProps(jshcalss->NumberOfProps());
207 }
208 } // namespace panda::ecmascript
209
210 #endif // ECMASCRIPT_JS_HCLASS_INL_H
211