• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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/byte_array.h"
22 #include "ecmascript/ic/proto_change_details.h"
23 #include "ecmascript/js_bigint.h"
24 #include "ecmascript/layout_info.h"
25 #include "ecmascript/layout_info-inl.h"
26 #include "ecmascript/mem/assert_scope.h"
27 #include "ecmascript/transitions_dictionary.h"
28 
29 namespace panda::ecmascript {
30 
AddTransitions(const JSThread * thread,const JSHandle<JSHClass> & parent,const JSHandle<JSHClass> & child,const JSHandle<JSTaggedValue> & key,PropertyAttributes attributes)31 void JSHClass::AddTransitions(const JSThread *thread, const JSHandle<JSHClass> &parent, const JSHandle<JSHClass> &child,
32                               const JSHandle<JSTaggedValue> &key, PropertyAttributes attributes)
33 {
34     UpdateRootHClass(thread, parent, child);
35     JSTaggedValue transitions = parent->GetTransitions(thread);
36     if (transitions.IsUndefined()) {
37         NotifyLeafHClassChanged(const_cast<JSThread *>(thread), parent);
38         JSTaggedValue weakChild = JSTaggedValue(child.GetTaggedValue().CreateAndGetWeakRef());
39         parent->SetTransitions(thread, weakChild);
40         return;
41     }
42     ASSERT(!parent->IsStable());
43     JSMutableHandle<TransitionsDictionary> dict(thread, JSTaggedValue::Undefined());
44     if (transitions.IsWeak()) {
45         auto cachedHClass = JSHClass::Cast(transitions.GetTaggedWeakRef());
46         if (cachedHClass->HasProps()) {
47             uint32_t last = cachedHClass->LastPropIndex();
48             LayoutInfo* layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout(thread).GetTaggedObject());
49             auto metaData = JSHandle<JSTaggedValue>(thread,
50                 JSTaggedValue(layoutInfo->GetAttr(thread, last).GetPropertyMetaData()));
51             auto lastKey = JSHandle<JSTaggedValue>(thread, layoutInfo->GetKey(thread, last));
52             auto lastHClass = JSHandle<JSTaggedValue>(thread, cachedHClass);
53             dict.Update(TransitionsDictionary::Create(thread));
54             transitions = TransitionsDictionary::PutIfAbsent(thread, dict, lastKey, lastHClass,
55                 metaData).GetTaggedValue();
56         }
57     }
58     auto metaData = JSHandle<JSTaggedValue>(thread, JSTaggedValue(attributes.GetPropertyMetaData()));
59     dict.Update(transitions);
60     transitions = TransitionsDictionary::PutIfAbsent(thread, dict, key, JSHandle<JSTaggedValue>(child),
61         metaData).GetTaggedValue();
62     parent->SetTransitions(thread, transitions);
63 }
64 
AddExtensionTransitions(const JSThread * thread,const JSHandle<JSHClass> & parent,const JSHandle<JSHClass> & child,const JSHandle<JSTaggedValue> & key)65 void JSHClass::AddExtensionTransitions(const JSThread *thread, const JSHandle<JSHClass> &parent,
66                                        const JSHandle<JSHClass> &child, const JSHandle<JSTaggedValue> &key)
67 {
68     auto attr = JSHandle<JSTaggedValue>(thread, PropertyAttributes(0).GetTaggedValue());
69     AddProtoTransitions(thread, parent, child, key, attr);
70 }
71 
AddProtoTransitions(const JSThread * thread,const JSHandle<JSHClass> & parent,const JSHandle<JSHClass> & child,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & proto)72 void JSHClass::AddProtoTransitions(const JSThread *thread, const JSHandle<JSHClass> &parent,
73                                    const JSHandle<JSHClass> &child, const JSHandle<JSTaggedValue> &key,
74                                    const JSHandle<JSTaggedValue> &proto)
75 {
76     ALLOW_LOCAL_TO_SHARE_WEAK_REF_HANDLE;
77     UpdateRootHClass(thread, parent, child);
78     JSTaggedValue transitions = parent->GetTransitions(thread);
79     JSMutableHandle<TransitionsDictionary> dict(thread, JSTaggedValue::Undefined());
80     if (transitions.IsUndefined()) {
81         NotifyLeafHClassChanged(const_cast<JSThread *>(thread), parent);
82         transitions = TransitionsDictionary::Create(thread).GetTaggedValue();
83     } else if (transitions.IsWeak()) {
84         auto cachedHClass = JSHClass::Cast(transitions.GetTaggedWeakRef());
85         if (cachedHClass->HasProps()) {
86             uint32_t last = cachedHClass->LastPropIndex();
87             LayoutInfo* layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout(thread).GetTaggedObject());
88             auto metaData = JSHandle<JSTaggedValue>(thread,
89                 JSTaggedValue(layoutInfo->GetAttr(thread, last).GetPropertyMetaData()));
90             auto lastKey = JSHandle<JSTaggedValue>(thread, layoutInfo->GetKey(thread, last));
91             auto lastHClass = JSHandle<JSTaggedValue>(thread, cachedHClass);
92             dict.Update(TransitionsDictionary::Create(thread));
93             transitions = TransitionsDictionary::PutIfAbsent(thread, dict, lastKey, lastHClass,
94                 metaData).GetTaggedValue();
95         }
96     }
97     ASSERT(!parent->IsStable());
98     dict.Update(transitions);
99     transitions =
100         TransitionsDictionary::PutIfAbsent(thread, dict, key, JSHandle<JSTaggedValue>(child), proto).GetTaggedValue();
101     parent->SetTransitions(thread, transitions);
102 }
103 
FindTransitions(const JSThread * thread,const JSTaggedValue & key,const JSTaggedValue & metaData,const Representation & rep)104 inline JSHClass *JSHClass::FindTransitions(const JSThread *thread, const JSTaggedValue &key,
105                                            const JSTaggedValue &metaData, const Representation &rep)
106 {
107     DISALLOW_GARBAGE_COLLECTION;
108     JSTaggedValue transitions = GetTransitions(thread);
109     if (transitions.IsUndefined()) {
110         return nullptr;
111     }
112     if (transitions.IsWeak()) {
113         auto cachedHClass = JSHClass::Cast(transitions.GetTaggedWeakRef());
114         if (cachedHClass->PropsIsEmpty()) {
115             return nullptr;
116         }
117         int last = static_cast<int>(cachedHClass->LastPropIndex());
118         LayoutInfo *layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout(thread).GetTaggedObject());
119         auto lastMetaData = layoutInfo->GetAttr(thread, last).GetPropertyMetaData();
120         auto lastKey = layoutInfo->GetKey(thread, last);
121         if (lastMetaData == metaData.GetInt() && key == lastKey) {
122             return CheckHClassForRep(thread, cachedHClass, rep);
123         }
124         return nullptr;
125     }
126 
127     ASSERT(transitions.IsTaggedArray());
128     TransitionsDictionary *dict = TransitionsDictionary::Cast(transitions.GetTaggedObject());
129     auto entry = dict->FindEntry(thread, key, metaData);
130     if (entry == -1) {
131         return nullptr;
132     }
133 
134     JSTaggedValue ret = dict->GetValue(thread, entry);
135     if (ret.IsUndefined()) {
136         return nullptr;
137     }
138 
139     return CheckHClassForRep(thread, JSHClass::Cast(ret.GetTaggedWeakRef()), rep);
140 }
141 
FindProtoTransitions(const JSThread * thread,const JSTaggedValue & key,const JSTaggedValue & proto)142 inline JSHClass *JSHClass::FindProtoTransitions(const JSThread *thread, const JSTaggedValue &key,
143                                                 const JSTaggedValue &proto)
144 {
145     DISALLOW_GARBAGE_COLLECTION;
146     JSTaggedValue transitions = GetTransitions(thread);
147     if (transitions.IsWeak() || !transitions.IsTaggedArray()) {
148         ASSERT(transitions.IsUndefined() || transitions.IsWeak());
149         return nullptr;
150     }
151     ASSERT(transitions.IsTaggedArray());
152     TransitionsDictionary *dict = TransitionsDictionary::Cast(transitions.GetTaggedObject());
153     auto entry = dict->FindEntry(thread, key, proto);
154     if (entry == -1) {
155         return nullptr;
156     }
157 
158     JSTaggedValue ret = dict->GetValue(thread, entry);
159     if (ret.IsUndefined()) {
160         return nullptr;
161     }
162 
163     return JSHClass::Cast(ret.GetTaggedWeakRef());
164 }
165 
RestoreElementsKindToGeneric(JSHClass * newJsHClass)166 inline void JSHClass::RestoreElementsKindToGeneric(JSHClass *newJsHClass)
167 {
168     newJsHClass->SetElementsKind(ElementsKind::GENERIC);
169 }
170 
CheckHClassForRep(const JSThread * thread,JSHClass * hclass,const Representation & rep)171 inline JSHClass *JSHClass::CheckHClassForRep(const JSThread *thread, JSHClass *hclass, const Representation &rep)
172 {
173     if (!hclass->IsAOT()) {
174         return hclass;
175     }
176     if (rep == Representation::NONE) {
177         return hclass;
178     }
179 
180     int last = static_cast<int>(hclass->LastPropIndex());
181     LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetLayout(thread).GetTaggedObject());
182     auto lastRep = layoutInfo->GetAttr(thread, last).GetRepresentation();
183     auto result = hclass;
184     if (lastRep == Representation::INT) {
185         if (rep != Representation::INT) {
186             result = nullptr;
187         }
188     } else if (lastRep == Representation::DOUBLE) {
189         if (rep != Representation::INT && rep != Representation::DOUBLE) {
190             result = nullptr;
191         }
192     }
193     return result;
194 }
195 
UpdatePropertyMetaData(const JSThread * thread,const JSTaggedValue & key,const PropertyAttributes & metaData)196 inline void JSHClass::UpdatePropertyMetaData(const JSThread *thread, [[maybe_unused]] const JSTaggedValue &key,
197                                              const PropertyAttributes &metaData)
198 {
199     DISALLOW_GARBAGE_COLLECTION;
200     ASSERT(!GetLayout(thread).IsNull());
201     LayoutInfo *layoutInfo = LayoutInfo::Cast(GetLayout(thread).GetTaggedObject());
202     ASSERT(layoutInfo->GetLength() != 0);
203     uint32_t entry = metaData.GetOffset();
204 
205     layoutInfo->SetNormalAttr(thread, entry, metaData);
206 }
207 
HasReferenceField()208 inline bool JSHClass::HasReferenceField()
209 {
210     auto type = GetObjectType();
211     switch (type) {
212         case JSType::LINE_STRING:
213         case JSType::JS_NATIVE_POINTER:
214             return false;
215         default:
216             return true;
217     }
218 }
219 
SizeFromJSHClass(TaggedObject * header)220 inline size_t JSHClass::SizeFromJSHClass(TaggedObject *header)
221 {
222     // CAUTION! Never use T::Cast(header) in this function
223     // it would cause issue during GC because hclass may forward to a new addres
224     // and the casting method would still use the old address.
225     auto type = GetObjectType();
226     size_t size = 0;
227     switch (type) {
228         case JSType::TAGGED_ARRAY:
229         case JSType::TAGGED_DICTIONARY:
230         case JSType::LEXICAL_ENV:
231         case JSType::SFUNCTION_ENV:
232         case JSType::SENDABLE_ENV:
233         case JSType::CONSTANT_POOL:
234         case JSType::AOT_LITERAL_INFO:
235         case JSType::VTABLE:
236         case JSType::COW_TAGGED_ARRAY:
237         case JSType::MUTANT_TAGGED_ARRAY:
238         case JSType::COW_MUTANT_TAGGED_ARRAY:
239         case JSType::PROFILE_TYPE_INFO:
240             size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(),
241                 reinterpret_cast<TaggedArray *>(header)->GetLength());
242             break;
243         case JSType::BYTE_ARRAY:
244             size = ByteArray::ComputeSize(reinterpret_cast<ByteArray *>(header)->GetByteLength(),
245                                           reinterpret_cast<ByteArray *>(header)->GetArrayLength());
246             size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
247             break;
248         case JSType::LINE_STRING:
249             size = LineString::ObjectSize(reinterpret_cast<BaseString* >(header));
250             size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
251             break;
252         case JSType::TREE_STRING:
253             size = TreeString::SIZE;
254             size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
255             break;
256         case JSType::SLICED_STRING:
257             size = SlicedString::SIZE;
258             size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
259             break;
260         case JSType::MACHINE_CODE_OBJECT:
261             size = reinterpret_cast<MachineCode *>(header)->GetMachineCodeObjectSize();
262             size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
263             break;
264         case JSType::BIGINT:
265             size = BigInt::ComputeSize(reinterpret_cast<BigInt *>(header)->GetLength());
266             size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
267             break;
268         default:
269             ASSERT(GetObjectSize() != 0);
270             size = GetObjectSize();
271             break;
272     }
273     ASSERT(AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)) == size);
274     return size;
275 }
276 
Copy(const JSThread * thread,const JSHClass * jshclass)277 inline void JSHClass::Copy(const JSThread *thread, const JSHClass *jshclass)
278 {
279     DISALLOW_GARBAGE_COLLECTION;
280 
281     // copy jshclass
282     SetPrototype(thread, jshclass->GetPrototype(thread));
283     SetBitField(jshclass->GetBitField());
284     SetIsAllTaggedProp(jshclass->IsAllTaggedProp());
285     SetNumberOfProps(jshclass->NumberOfProps());
286 }
287 
FindRootHClass(const JSThread * thread,JSHClass * hclass)288 inline JSHClass *JSHClass::FindRootHClass(const JSThread *thread, JSHClass *hclass)
289 {
290     auto root = hclass;
291     while (!ProfileType(root->GetProfileType()).IsRootType()) {
292         auto parent = root->GetParent(thread);
293         if (!parent.IsJSHClass()) {
294             break;
295         }
296         root = JSHClass::Cast(parent.GetTaggedObject());
297     }
298     return root;
299 }
300 
FindProtoHClass(const JSThread * thread,JSHClass * hclass)301 inline JSTaggedValue JSHClass::FindProtoHClass(const JSThread *thread, JSHClass *hclass)
302 {
303     auto proto = hclass->GetProto(thread);
304     if (proto.IsJSObject()) {
305         auto prototypeObj = JSObject::Cast(proto);
306         return JSTaggedValue(prototypeObj->GetClass());
307     }
308     return JSTaggedValue::Undefined();
309 }
310 
FindProtoRootHClass(const JSThread * thread,JSHClass * hclass)311 inline JSTaggedValue JSHClass::FindProtoRootHClass(const JSThread *thread, JSHClass *hclass)
312 {
313     auto proto = hclass->GetProto(thread);
314     if (proto.IsJSObject()) {
315         auto prototypeObj = JSObject::Cast(proto);
316         auto prototypeHClass = prototypeObj->GetClass();
317         return JSTaggedValue(JSHClass::FindRootHClass(thread, prototypeHClass));
318     }
319     return JSTaggedValue::Undefined();
320 }
321 
UpdateRootHClass(const JSThread * thread,const JSHandle<JSHClass> & parent,const JSHandle<JSHClass> & child)322 inline void JSHClass::UpdateRootHClass(const JSThread *thread, const JSHandle<JSHClass> &parent,
323                                        const JSHandle<JSHClass> &child)
324 {
325     if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
326         child->SetParent(thread, parent);
327     }
328 }
329 
FindPropertyEntry(const JSThread * thread,JSHClass * hclass,JSTaggedValue key)330 inline int JSHClass::FindPropertyEntry(const JSThread *thread, JSHClass *hclass, JSTaggedValue key)
331 {
332     DISALLOW_GARBAGE_COLLECTION;
333     LayoutInfo *layout = LayoutInfo::Cast(hclass->GetLayout(thread).GetTaggedObject());
334     uint32_t propsNumber = hclass->NumberOfProps();
335     int entry = layout->FindElementWithCache(thread, hclass, key, propsNumber);
336     return entry;
337 }
338 
CompleteObjSizeTracking(const JSThread * thread)339 inline void JSHClass::CompleteObjSizeTracking(const JSThread *thread)
340 {
341     if (!IsObjSizeTrackingInProgress()) {
342         return;
343     }
344     uint32_t finalInObjPropsNum = JSHClass::VisitTransitionAndFindMaxNumOfProps(thread, this);
345     if (finalInObjPropsNum < GetInlinedProperties()) {
346         // UpdateObjSize with finalInObjPropsNum
347         JSHClass::VisitTransitionAndUpdateObjSize(thread, this, finalInObjPropsNum);
348     }
349     SetConstructionCounter(0); // fini ObjSizeTracking
350 }
351 
ObjSizeTrackingStep(const JSThread * thread)352 inline void JSHClass::ObjSizeTrackingStep(const JSThread *thread)
353 {
354     if (!IsObjSizeTrackingInProgress()) {
355         return;
356     }
357     uint32_t constructionCounter = GetConstructionCounter();
358     ASSERT(constructionCounter != 0);
359     SetConstructionCounter(--constructionCounter);
360     if (constructionCounter == 0) {
361         uint32_t finalInObjPropsNum = JSHClass::VisitTransitionAndFindMaxNumOfProps(thread, this);
362         if (finalInObjPropsNum < GetInlinedProperties()) {
363             // UpdateObjSize with finalInObjPropsNum
364             JSHClass::VisitTransitionAndUpdateObjSize(thread, this, finalInObjPropsNum);
365         }
366     }
367 }
368 
369 template<bool isForAot>
MarkProtoChanged(const JSThread * thread,const JSHandle<JSHClass> & jshclass)370 void JSHClass::MarkProtoChanged(const JSThread *thread, const JSHandle<JSHClass> &jshclass)
371 {
372     DISALLOW_GARBAGE_COLLECTION;
373     ASSERT(jshclass->IsPrototype());
374     JSTaggedValue enumCache = jshclass->GetEnumCache(thread);
375     JSTaggedValue markerValue = jshclass->GetProtoChangeMarker(thread);
376     // Used in for-in.
377     if (enumCache.IsEnumCache()) {
378         EnumCache::Cast(enumCache)->SetInvalidState(thread);
379     }
380     if (markerValue.IsProtoChangeMarker()) {
381         ProtoChangeMarker *protoChangeMarker = ProtoChangeMarker::Cast(markerValue.GetTaggedObject());
382         if constexpr (isForAot) {
383             protoChangeMarker->SetNotFoundHasChanged(true);
384         } else {
385             protoChangeMarker->SetHasChanged(true);
386         }
387     }
388 }
389 
390 template<bool isForAot /* = false*/>
NoticeThroughChain(const JSThread * thread,const JSHandle<JSHClass> & jshclass,JSTaggedValue addedKey)391 void JSHClass::NoticeThroughChain(const JSThread *thread, const JSHandle<JSHClass> &jshclass,
392                                   JSTaggedValue addedKey)
393 {
394     DISALLOW_GARBAGE_COLLECTION;
395     MarkProtoChanged<isForAot>(thread, jshclass);
396     JSTaggedValue protoDetailsValue = jshclass->GetProtoChangeDetails(thread);
397     if (!protoDetailsValue.IsProtoChangeDetails()) {
398         return;
399     }
400     JSTaggedValue listenersValue =
401         ProtoChangeDetails::Cast(protoDetailsValue.GetTaggedObject())->GetChangeListener(thread);
402     if (!listenersValue.IsTaggedArray()) {
403         return;
404     }
405     ChangeListener *listeners = ChangeListener::Cast(listenersValue.GetTaggedObject());
406     for (uint32_t i = 0; i < listeners->GetEnd(); i++) {
407         JSTaggedValue temp = listeners->Get(thread, i);
408         if (temp.IsJSHClass()) {
409             NoticeThroughChain<isForAot>(thread,
410                 JSHandle<JSHClass>(thread, listeners->Get(thread, i).GetTaggedObject()), addedKey);
411         }
412     }
413 }
414 
415 template<bool checkDuplicateKeys /* = false*/>
AddPropertyToNewHClass(const JSThread * thread,JSHandle<JSHClass> & jshclass,JSHandle<JSHClass> & newJsHClass,const JSHandle<JSTaggedValue> & key,const PropertyAttributes & attr)416 void JSHClass::AddPropertyToNewHClass(const JSThread *thread, JSHandle<JSHClass> &jshclass,
417                                       JSHandle<JSHClass> &newJsHClass,
418                                       const JSHandle<JSTaggedValue> &key,
419                                       const PropertyAttributes &attr)
420 {
421     ASSERT(!jshclass->IsDictionaryMode());
422     ASSERT(!newJsHClass->IsDictionaryMode());
423     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
424     // Add Property and metaData
425     uint32_t offset = attr.GetOffset();
426     newJsHClass->IncNumberOfProps();
427 
428     {
429         JSMutableHandle<LayoutInfo> layoutInfoHandle(thread, newJsHClass->GetLayout(thread));
430 
431         if (layoutInfoHandle->NumberOfElements() != static_cast<int>(offset)) {
432             layoutInfoHandle.Update(factory->CopyAndReSort(layoutInfoHandle, offset, offset + 1));
433             newJsHClass->SetLayout(thread, layoutInfoHandle);
434         } else if (layoutInfoHandle->GetPropertiesCapacity() <= static_cast<int>(offset)) {  // need to Grow
435             layoutInfoHandle.Update(
436                 factory->ExtendLayoutInfo(layoutInfoHandle, offset));
437             newJsHClass->SetLayout(thread, layoutInfoHandle);
438         }
439         layoutInfoHandle->AddKey<checkDuplicateKeys>(thread, offset, key.GetTaggedValue(), attr);
440     }
441 
442     // Add newClass to old hclass's transitions.
443     AddTransitions(thread, jshclass, newJsHClass, key, attr);
444 
445     if UNLIKELY(key.GetTaggedValue() == thread->GlobalConstants()->GetConstructorString()
446         && (jshclass->IsJSArray() || jshclass->IsTypedArray())) {
447         newJsHClass->SetHasConstructor(true);
448     }
449 }
450 
AddInlinedPropToHClass(const JSThread * thread,const PropertyDescriptor & desc,size_t attrOffset,const JSHandle<JSTaggedValue> & key,JSHandle<JSHClass> & hClass)451 void JSHClass::AddInlinedPropToHClass(const JSThread *thread, const PropertyDescriptor &desc, size_t attrOffset,
452                                       const JSHandle<JSTaggedValue> &key, JSHandle<JSHClass> &hClass)
453 {
454     ecmascript::PropertyAttributes attr(desc);
455     attr.SetIsInlinedProps(true);
456     attr.SetOffset(attrOffset);
457     attr.SetRepresentation(ecmascript::Representation::TAGGED);
458     // Classes defined by napi_define_class are different from each other, there's no need to consider about transition.
459     JSHClass::AddPropertyToNewHClassWithoutTransition(thread, hClass, key, attr);
460 }
461 
462 template<bool checkDuplicateKeys /* = false*/>
SetPropertyOfObjHClass(const JSThread * thread,JSHandle<JSHClass> & jshclass,const JSHandle<JSTaggedValue> & key,const PropertyAttributes & attr,const Representation & rep,bool specificInlinedProps,uint32_t specificNumInlinedProps)463 JSHandle<JSHClass> JSHClass::SetPropertyOfObjHClass(const JSThread *thread, JSHandle<JSHClass> &jshclass,
464                                                     const JSHandle<JSTaggedValue> &key,
465                                                     const PropertyAttributes &attr, const Representation &rep,
466                                                     bool specificInlinedProps, uint32_t specificNumInlinedProps)
467 {
468     JSHClass *newClass = jshclass->FindTransitions(thread,
469         key.GetTaggedValue(), JSTaggedValue(attr.GetPropertyMetaData()), rep);
470     if (newClass != nullptr) {
471         newClass->SetPrototype(thread, jshclass->GetPrototype(thread));
472         return JSHandle<JSHClass>(thread, newClass);
473     }
474 
475     JSHandle<JSHClass> newJsHClass = JSHClass::Clone(thread, jshclass, specificInlinedProps, specificNumInlinedProps);
476     AddPropertyToNewHClass<checkDuplicateKeys>(thread, jshclass, newJsHClass, key, attr);
477     return newJsHClass;
478 }
479 }  // namespace panda::ecmascript
480 
481 #endif  // ECMASCRIPT_JS_HCLASS_INL_H
482