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