• 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     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