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