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