• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 #include "ecmascript/js_hclass-inl.h"
17 #include "ecmascript/js_object.h"
18 #include "ecmascript/global_env.h"
19 #include "ecmascript/ic/proto_change_details.h"
20 #include "ecmascript/layout_info.h"
21 #include "ecmascript/object_factory-inl.h"
22 #include "ecmascript/tagged_dictionary.h"
23 #include "ecmascript/tests/test_helper.h"
24 
25 using namespace panda;
26 using namespace panda::ecmascript;
27 
28 namespace panda::test {
29 class JSHClassTest : public BaseTestWithScope<false> {
30 };
31 
HWTEST_F_L0(JSHClassTest,InitializeClass)32 HWTEST_F_L0(JSHClassTest, InitializeClass)
33 {
34     EcmaVM *vm = thread->GetEcmaVM();
35     ObjectFactory *factory = vm->GetFactory();
36     JSHandle<JSTaggedValue> nullHandle(thread, JSTaggedValue::Null());
37     // Call NewEcmaHClass function set object properties
38     JSHandle<JSHClass> objectClass =
39         factory->NewEcmaHClass(TaggedArray::SIZE, JSType::TAGGED_ARRAY, nullHandle);
40     // Get object properties
41     EXPECT_EQ(objectClass->GetLayout(), JSTaggedValue::Null());
42     EXPECT_EQ(objectClass->GetPrototype(), JSTaggedValue::Null());
43     EXPECT_EQ(objectClass->GetObjectType(), JSType::TAGGED_ARRAY);
44     EXPECT_TRUE(objectClass->IsExtensible());
45     EXPECT_TRUE(!objectClass->IsPrototype());
46     EXPECT_EQ(objectClass->GetTransitions(), JSTaggedValue::Undefined());
47     EXPECT_EQ(objectClass->GetProtoChangeMarker(), JSTaggedValue::Null());
48     EXPECT_EQ(objectClass->GetProtoChangeDetails(), JSTaggedValue::Null());
49     EXPECT_EQ(objectClass->GetEnumCache(), JSTaggedValue::Null());
50 }
51 
HWTEST_F_L0(JSHClassTest,SizeFromJSHClass)52 HWTEST_F_L0(JSHClassTest, SizeFromJSHClass)
53 {
54     EcmaVM *vm = thread->GetEcmaVM();
55     ObjectFactory *factory = vm->GetFactory();
56     JSHandle<JSTaggedValue> nullHandle(thread, JSTaggedValue::Null());
57 
58     JSHandle<JSHClass> objectClass = factory->NewEcmaHClass(TaggedArray::SIZE, JSType::TAGGED_ARRAY, nullHandle);
59     EXPECT_TRUE(*objectClass != nullptr);
60     size_t objectSize;
61 #ifndef PANDA_TARGET_32
62     objectSize = objectClass->SizeFromJSHClass(*objectClass);
63     EXPECT_EQ(objectSize, 40U);
64 #endif
65     EcmaString *string = EcmaStringAccessor::CreateEmptyString(vm);
66     objectSize = string->GetClass()->SizeFromJSHClass(string);
67     EXPECT_EQ(objectSize, 16U);
68     string = factory->AllocTreeStringObject();
69     objectSize = string->GetClass()->SizeFromJSHClass(string);
70     EXPECT_EQ(objectSize, 32U);
71 
72     objectClass = factory->NewEcmaHClass(MachineCode::SIZE, JSType::MACHINE_CODE_OBJECT, nullHandle);
73     objectSize = objectClass->SizeFromJSHClass(*objectClass);
74     EXPECT_EQ(objectSize, 64U);
75     // size is an integral multiple of eight
76     objectClass = factory->NewEcmaHClass(JSObject::SIZE - 1, JSType::JS_OBJECT, nullHandle);
77     objectSize = objectClass->SizeFromJSHClass(*objectClass);
78     EXPECT_EQ(objectSize, 56U);
79 
80     objectClass = factory->NewEcmaHClass(JSObject::SIZE + 1, JSType::JS_OBJECT, nullHandle);
81     objectSize = objectClass->SizeFromJSHClass(*objectClass);
82     EXPECT_EQ(objectSize, 64U);
83 
84     objectClass = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, nullHandle);
85     objectSize = objectClass->SizeFromJSHClass(*objectClass);
86     EXPECT_EQ(objectSize, 64U);
87 }
88 
HWTEST_F_L0(JSHClassTest,HasReferenceField)89 HWTEST_F_L0(JSHClassTest, HasReferenceField)
90 {
91     EcmaVM *vm = thread->GetEcmaVM();
92     ObjectFactory *factory = vm->GetFactory();
93     JSHandle<JSTaggedValue> nullHandle(thread, JSTaggedValue::Null());
94 
95     JSHandle<JSHClass> obj1Class = factory->NewEcmaHClass(TaggedArray::SIZE, JSType::LINE_STRING, nullHandle);
96     JSHandle<JSHClass> obj2Class = factory->NewEcmaHClass(TaggedArray::SIZE, JSType::TREE_STRING, nullHandle);
97     JSHandle<JSHClass> obj3Class =
98         factory->NewEcmaHClass(TaggedArray::SIZE, JSType::JS_NATIVE_POINTER, nullHandle);
99     JSHandle<JSHClass> obj4Class = factory->NewEcmaHClass(TaggedArray::SIZE, JSType::JS_OBJECT, nullHandle);
100     JSHandle<JSHClass> obj5Class = factory->NewEcmaHClass(TaggedArray::SIZE, JSType::SLICED_STRING, nullHandle);
101     EXPECT_FALSE(obj1Class->HasReferenceField());
102     EXPECT_TRUE(obj2Class->HasReferenceField());
103     EXPECT_FALSE(obj3Class->HasReferenceField());
104     EXPECT_TRUE(obj4Class->HasReferenceField());
105     EXPECT_TRUE(obj5Class->HasReferenceField());
106 }
107 
HWTEST_F_L0(JSHClassTest,Clone)108 HWTEST_F_L0(JSHClassTest, Clone)
109 {
110     EcmaVM *vm = thread->GetEcmaVM();
111     ObjectFactory *factory = vm->GetFactory();
112     JSHandle<JSTaggedValue> nullHandle(thread, JSTaggedValue::Null());
113 
114     JSHandle<JSHClass> objectClass = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, nullHandle);
115     // withoutInlinedProperties is false
116     JSHandle<JSHClass> cloneClass = JSHClass::Clone(thread, objectClass, false);
117     EXPECT_TRUE(*cloneClass != nullptr);
118     EXPECT_TRUE(objectClass->GetObjectSize() == cloneClass->GetObjectSize());
119     EXPECT_EQ(cloneClass->GetObjectSize(), 64U); // 64 : 64 not missing the size of inlinedproperties
120     EXPECT_TRUE(objectClass->GetLayout() == cloneClass->GetLayout());
121     EXPECT_EQ(JSTaggedValue::SameValue(objectClass->GetPrototype(), cloneClass->GetPrototype()), true);
122     EXPECT_TRUE(objectClass->GetBitField() == cloneClass->GetBitField());
123     EXPECT_TRUE(objectClass->GetBitField1() == cloneClass->GetBitField1());
124     EXPECT_TRUE(objectClass->NumberOfProps() == cloneClass->NumberOfProps());
125     EXPECT_EQ(cloneClass->GetNextInlinedPropsIndex(), 0); // 0 : 0 mean index
126     // withoutInlinedProperties is true
127     cloneClass = JSHClass::Clone(thread, objectClass, true);
128     EXPECT_TRUE(*cloneClass != nullptr);
129     EXPECT_TRUE(objectClass->GetObjectSize() > cloneClass->GetObjectSize());
130     EXPECT_EQ(cloneClass->GetObjectSize(), 32U); // 32 : 32 missing the size of inlinedproperties
131     EXPECT_TRUE(objectClass->GetLayout() == cloneClass->GetLayout());
132     EXPECT_EQ(JSTaggedValue::SameValue(objectClass->GetPrototype(), cloneClass->GetPrototype()), true);
133     EXPECT_TRUE(objectClass->GetBitField() == cloneClass->GetBitField());
134     EXPECT_TRUE(objectClass->GetBitField1() > cloneClass->GetBitField1());
135     EXPECT_TRUE(objectClass->NumberOfProps() == cloneClass->NumberOfProps());
136     EXPECT_EQ(cloneClass->GetNextNonInlinedPropsIndex(), 0); // 0 : 0 mean index
137 }
138 
HWTEST_F_L0(JSHClassTest,TransitionElementsToDictionary)139 HWTEST_F_L0(JSHClassTest, TransitionElementsToDictionary)
140 {
141     EcmaVM *vm = thread->GetEcmaVM();
142     ObjectFactory *factory = vm->GetFactory();
143 
144     JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
145     JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
146     JSHandle<JSObject> jsObject = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
147     JSHandle<JSHClass> objectClass(thread, jsObject->GetJSHClass());
148     JSHandle<JSTaggedValue> objKey1(factory->NewFromASCII("key1"));
149     JSHandle<JSTaggedValue> objKey2(factory->NewFromASCII("key2"));
150     JSHandle<JSTaggedValue> objKey3(factory->NewFromASCII("key3"));
151 
152     JSHandle<JSTaggedValue> objValue1(thread, JSTaggedValue(1));
153     JSHandle<JSTaggedValue> objValue2(thread, JSTaggedValue(2));
154     JSHandle<JSTaggedValue> objValue3(thread, JSTaggedValue(3));
155 
156     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(jsObject), objKey1, objValue1);
157     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(jsObject), objKey2, objValue2);
158     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(jsObject), objKey3, objValue3);
159     // class is not dictionary mode
160     EXPECT_FALSE(jsObject->GetJSHClass()->IsDictionaryMode());
161     ElementsKind oldKind = jsObject->GetJSHClass()->GetElementsKind();
162     JSHClass::TransitionElementsToDictionary(thread, jsObject);
163     JSObject::TryMigrateToGenericKindForJSObject(thread, jsObject, oldKind);
164     auto resultDict = NameDictionary::Cast(jsObject->GetProperties().GetTaggedObject());
165     EXPECT_TRUE(resultDict != nullptr);
166     EXPECT_EQ(resultDict->EntriesCount(), 3); // 3 : 3 entry
167 
168     JSHandle<JSHClass> dictionaryClass(thread, jsObject->GetJSHClass());
169     EXPECT_TRUE(dictionaryClass->IsDictionaryMode());
170     EXPECT_EQ(dictionaryClass->GetObjectSize() + 32U, objectClass->GetObjectSize());
171     EXPECT_TRUE(dictionaryClass->IsDictionaryElement());
172     EXPECT_FALSE(dictionaryClass->IsStableElements());
173 }
174 
CreateJSHClass(JSThread * thread)175 static JSHandle<JSHClass> CreateJSHClass(JSThread *thread)
176 {
177     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
178     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
179     JSHandle<JSTaggedValue> objectFuncPrototype = env->GetObjectFunctionPrototype();
180     JSHandle<JSHClass> hclass = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, objectFuncPrototype);
181     return hclass;
182 }
183 
HWTEST_F_L0(JSHClassTest,SetPropertyOfObjHClass_001)184 HWTEST_F_L0(JSHClassTest, SetPropertyOfObjHClass_001)
185 {
186     EcmaVM *vm = thread->GetEcmaVM();
187     ObjectFactory *factory = vm->GetFactory();
188     JSHandle<JSTaggedValue> accessorData(factory->NewAccessorData());
189     JSHandle<EcmaString> keyHandle = factory->NewFromASCII("key");
190     JSHandle<JSTaggedValue> keyHandle0(factory->NewFromASCII("key0"));
191     JSHandle<JSTaggedValue> keyHandle2(factory->NewFromASCII("key2"));
192     JSHandle<JSTaggedValue> keyHandle4(factory->NewFromASCII("key4"));
193     // empty layoutInfo
194     JSHandle<JSHClass> parentsClass = CreateJSHClass(thread);
195 
196     uint32_t length = 6;
197     JSHandle<TaggedArray> properties = factory->NewTaggedArray(length);
198     for (int i = 0; i < static_cast<int>(length); i++) {
199         if (i % 2 == 0) {
200             JSHandle<JSTaggedValue> newValue(thread, JSTaggedValue(i));
201             JSHandle<EcmaString> newKey =
202                 factory->ConcatFromString(keyHandle, JSTaggedValue::ToString(thread, newValue));
203             properties->Set(thread, i, newKey.GetTaggedValue());
204             continue;
205         }
206         properties->Set(thread, i, accessorData.GetTaggedValue());
207     }
208     JSHandle<JSHClass> childClass = factory->SetLayoutInObjHClass(properties, 3, parentsClass);
209     JSHandle<JSObject> childObj = factory->NewJSObject(childClass);
210 
211     std::vector<JSTaggedValue> keyVector;
212     JSObject::GetAllKeysForSerialization(childObj, keyVector);
213     EXPECT_EQ(keyVector.size(), 3U);
214     EXPECT_TRUE(JSObject::HasProperty(thread, childObj, keyHandle0));
215     EXPECT_TRUE(JSObject::HasProperty(thread, childObj, keyHandle2));
216     EXPECT_TRUE(JSObject::HasProperty(thread, childObj, keyHandle4));
217 }
218 
HWTEST_F_L0(JSHClassTest,SetPropertyOfObjHClass_002)219 HWTEST_F_L0(JSHClassTest, SetPropertyOfObjHClass_002)
220 {
221     EcmaVM *vm = thread->GetEcmaVM();
222     ObjectFactory *factory = vm->GetFactory();
223     JSHandle<JSHClass> objClass = CreateJSHClass(thread);
224     JSHandle<JSObject> Obj1 = factory->NewJSObject(objClass);
225     JSHandle<JSObject> Obj2 = factory->NewJSObject(objClass);
226     PropertyAttributes attr = PropertyAttributes::Default();
227 
228     JSHandle<JSTaggedValue> keyE(factory->NewFromASCII("e"));
229     JSHandle<JSTaggedValue> keyF(factory->NewFromASCII("f"));
230     // not empty layoutInfo
231     auto valueE = JSHandle<JSTaggedValue>(thread, JSTaggedValue(7));
232     auto valueF = JSHandle<JSTaggedValue>(thread, JSTaggedValue(8));
233     JSObject::SetProperty(thread, Obj1, keyE, valueE);
234     JSObject::SetProperty(thread, Obj2, keyF, valueE);
235 
236     auto repE = PropertyAttributes::TranslateToRep(valueE.GetTaggedValue());
237     JSHandle<JSHClass> propertyHclass = JSHClass::SetPropertyOfObjHClass(thread, objClass, keyE, attr, repE);
238     JSHandle<JSHClass> obj1Class(thread, Obj1->GetClass());
239     EXPECT_TRUE(propertyHclass == obj1Class);
240 
241     auto repF = PropertyAttributes::TranslateToRep(valueF.GetTaggedValue());
242     propertyHclass = JSHClass::SetPropertyOfObjHClass(thread, objClass, keyF, attr, repF);
243     JSHandle<JSHClass> obj2Class(thread, Obj2->GetClass());
244     EXPECT_TRUE(propertyHclass == obj2Class);
245 }
246 
HWTEST_F_L0(JSHClassTest,AddProperty)247 HWTEST_F_L0(JSHClassTest, AddProperty)
248 {
249     EcmaVM *vm = thread->GetEcmaVM();
250     ObjectFactory *factory = vm->GetFactory();
251     JSHandle<EcmaString> keyHandle = factory->NewFromASCII("key");
252     JSHandle<JSTaggedValue> keyHandle0(factory->NewFromASCII("key0"));
253     JSHandle<JSTaggedValue> keyHandle1(factory->NewFromASCII("key1"));
254     JSHandle<JSTaggedValue> keyHandle2(factory->NewFromASCII("key2"));
255     PropertyAttributes attr = PropertyAttributes::Default();
256     attr.SetIsInlinedProps(true);
257     // empty layoutInfo
258     JSHandle<JSHClass> objClass1 = CreateJSHClass(thread);
259     JSHandle<JSObject> Obj = factory->NewJSObject(objClass1);
260     JSHandle<JSHClass> objClass(thread, Obj->GetClass());
261     EXPECT_FALSE(objClass1 != objClass);
262     int keyLength = 3;
263     for (int i = 0; i <keyLength; i++) {
264         JSHandle<JSTaggedValue> keyValue(thread, JSTaggedValue(i));
265         JSHandle<JSTaggedValue> keyHandleI(
266             factory->ConcatFromString(keyHandle, JSTaggedValue::ToString(thread, keyValue)));
267         attr.SetOffset(i);
268         ElementsKind oldKind = Obj->GetJSHClass()->GetElementsKind();
269         JSHClass::AddProperty(thread, Obj, keyHandleI, attr);
270         JSObject::TryMigrateToGenericKindForJSObject(thread, Obj, oldKind);
271     }
272     EXPECT_TRUE(objClass1 == objClass);
273     std::vector<JSTaggedValue> keyVector;
274     JSObject::GetAllKeysForSerialization(Obj, keyVector);
275     EXPECT_EQ(keyVector.size(), 3U);
276     EXPECT_TRUE(JSObject::HasProperty(thread, Obj, keyHandle0));
277     EXPECT_TRUE(JSObject::HasProperty(thread, Obj, keyHandle1));
278     EXPECT_TRUE(JSObject::HasProperty(thread, Obj, keyHandle2));
279 }
280 
HWTEST_F_L0(JSHClassTest,TransitionExtension)281 HWTEST_F_L0(JSHClassTest, TransitionExtension)
282 {
283     EcmaVM *vm = thread->GetEcmaVM();
284     ObjectFactory *factory = vm->GetFactory();
285     JSHandle<JSTaggedValue> preExtensionsKey = thread->GlobalConstants()->GetHandledPreventExtensionsString();
286     JSHandle<JSTaggedValue> keyHandle0(factory->NewFromASCII("key0"));
287     JSHandle<JSTaggedValue> keyHandle1(factory->NewFromASCII("key1"));
288     JSHandle<JSTaggedValue> keyHandle2(factory->NewFromASCII("key2"));
289     PropertyAttributes attr = PropertyAttributes(0);
290     attr.SetIsInlinedProps(true);
291     JSHandle<JSHClass> obj1Class = CreateJSHClass(thread);
292     JSHandle<JSHClass> obj2Class = CreateJSHClass(thread);
293     obj2Class->SetExtensible(true);
294     JSHandle<JSObject> Obj1 = factory->NewJSObject(obj1Class);
295     JSHandle<JSObject> Obj2 = factory->NewJSObject(obj2Class);
296     JSObject::SetProperty(thread, Obj2, keyHandle0, JSHandle<JSTaggedValue>(thread, JSTaggedValue(7)));
297     JSObject::SetProperty(thread, Obj2, keyHandle1, JSHandle<JSTaggedValue>(thread, JSTaggedValue(8)));
298     JSObject::SetProperty(thread, Obj2, keyHandle2, JSHandle<JSTaggedValue>(thread, JSTaggedValue(9)));
299     // obj has key "PreventExtensions"
300     ElementsKind oldKind = Obj1->GetJSHClass()->GetElementsKind();
301     JSHClass::AddProperty(thread, Obj1, preExtensionsKey, attr);
302     JSObject::TryMigrateToGenericKindForJSObject(thread, Obj1, oldKind);
303     JSHandle<JSHClass> newClass1 = JSHClass::TransitionExtension(thread, obj1Class);
304     JSHandle<JSHClass> objClass(thread, Obj1->GetClass());
305     EXPECT_TRUE(newClass1 == objClass);
306     // obj has no key "PreventExtensions"
307     JSHandle<JSHClass> newClass2 = JSHClass::TransitionExtension(thread, obj2Class);
308     EXPECT_FALSE(newClass2->IsExtensible());
309     JSHandle<TransitionsDictionary> dictionary(thread, obj2Class->GetTransitions());
310     // find key
311     std::vector<JSTaggedValue> keyVector;
312     dictionary->GetAllKeysIntoVector(keyVector);
313     EXPECT_EQ(keyVector[0], keyHandle0.GetTaggedValue());
314     EXPECT_EQ(keyVector[1], preExtensionsKey.GetTaggedValue());
315 }
316 
HWTEST_F_L0(JSHClassTest,TransitionProto)317 HWTEST_F_L0(JSHClassTest, TransitionProto)
318 {
319     EcmaVM *vm = thread->GetEcmaVM();
320     ObjectFactory *factory = vm->GetFactory();
321     JSHandle<GlobalEnv> env =vm->GetGlobalEnv();
322     JSHandle<JSTaggedValue> funcPrototype = env->GetFunctionPrototype();
323     JSHandle<JSTaggedValue> prototypeKey = thread->GlobalConstants()->GetHandledPrototypeString();
324     JSHandle<JSTaggedValue> obj1Key(factory->NewFromASCII("key0"));
325     JSHandle<JSTaggedValue> obj2Key(factory->NewFromASCII("key1"));
326     JSHandle<JSTaggedValue> obj3Key(factory->NewFromASCII("key2"));
327     PropertyAttributes attr = PropertyAttributes(0);
328     attr.SetIsInlinedProps(true);
329     JSHandle<JSHClass> objClass = CreateJSHClass(thread);
330     JSHandle<JSObject> Obj = factory->NewJSObject(objClass);
331     // obj has no key "prototype"
332     ElementsKind oldKind = Obj->GetJSHClass()->GetElementsKind();
333     JSHClass::AddProperty(thread, Obj, obj1Key, attr);
334     JSObject::TryMigrateToGenericKindForJSObject(thread, Obj, oldKind);
335     oldKind = Obj->GetJSHClass()->GetElementsKind();
336     JSHClass::AddProperty(thread, Obj, obj2Key, attr);
337     JSObject::TryMigrateToGenericKindForJSObject(thread, Obj, oldKind);
338     oldKind = Obj->GetJSHClass()->GetElementsKind();
339     JSHClass::AddProperty(thread, Obj, obj3Key, attr);
340     JSObject::TryMigrateToGenericKindForJSObject(thread, Obj, oldKind);
341     JSHandle<JSHClass> newClass = JSHClass::TransitionProto(thread, objClass, funcPrototype);
342     EXPECT_EQ(newClass->GetPrototype(), funcPrototype.GetTaggedValue());
343     JSHandle<TransitionsDictionary> transitionDictionary(thread, objClass->GetTransitions());
344     // find key
345     std::vector<JSTaggedValue> keyVector;
346     transitionDictionary->GetAllKeysIntoVector(keyVector);
347     EXPECT_EQ(keyVector.size(), 2U);
348     EXPECT_EQ(keyVector[0], obj1Key.GetTaggedValue());
349     EXPECT_EQ(keyVector[1], prototypeKey.GetTaggedValue());
350 }
351 
HWTEST_F_L0(JSHClassTest,TransitionToDictionary)352 HWTEST_F_L0(JSHClassTest, TransitionToDictionary)
353 {
354     EcmaVM *vm = thread->GetEcmaVM();
355     ObjectFactory *factory = vm->GetFactory();
356     JSHandle<JSTaggedValue> obj1Key(factory->NewFromASCII("key1"));
357     JSHandle<JSTaggedValue> obj2Key(factory->NewFromASCII("key2"));
358     JSHandle<JSTaggedValue> obj3Key(factory->NewFromASCII("key3"));
359     JSHandle<JSObject> nullHandle(thread, JSTaggedValue::Null());
360     JSHandle<JSHClass> objClass = CreateJSHClass(thread);
361     objClass->SetIsPrototype(true);
362     JSHandle<JSObject> Obj0 = factory->NewJSObject(objClass);
363     JSHandle<JSHClass> obj0Class1(thread, Obj0->GetJSHClass());
364     JSHandle<JSObject> Obj1 = JSObject::ObjectCreate(thread, nullHandle);
365     JSHandle<JSObject> Obj2 = JSObject::ObjectCreate(thread, Obj1);
366     JSHandle<JSHClass> obj2Class(thread, Obj2->GetJSHClass());
367     JSHandle<JSObject> Obj3 = JSObject::ObjectCreate(thread, Obj2);
368     JSObject::SetProperty(thread, Obj1, obj1Key, JSHandle<JSTaggedValue>(thread, JSTaggedValue(100)));
369     JSObject::SetProperty(thread, Obj2, obj2Key, JSHandle<JSTaggedValue>(thread, JSTaggedValue(101)));
370     JSObject::SetProperty(thread, Obj3, obj3Key, JSHandle<JSTaggedValue>(thread, JSTaggedValue(102)));
371     // empty object
372     JSObject::TransitionToDictionary(thread, Obj0);
373     JSHandle<JSHClass> obj0Class(thread, Obj0->GetClass());
374     EXPECT_TRUE(obj0Class->GetObjectSize() < obj0Class1->GetObjectSize());
375     EXPECT_EQ(obj0Class->NumberOfProps(), 0U);
376     EXPECT_TRUE(obj0Class->IsDictionaryMode());
377     EXPECT_TRUE(obj0Class->IsPrototype());
378     // not empty object
379     JSHandle<JSHClass> obj3Class(thread, Obj3->GetJSHClass());
380     JSHClass::EnableProtoChangeMarker(thread, obj3Class);
381     JSObject::TransitionToDictionary(thread, Obj2);
382     // refresh users
383     JSHandle<JSHClass> obj1Class(thread, Obj1->GetJSHClass());
384     JSTaggedValue protoDetails = obj1Class->GetProtoChangeDetails();
385     EXPECT_TRUE(protoDetails.IsProtoChangeDetails());
386     JSTaggedValue listenersValue = ProtoChangeDetails::Cast(protoDetails.GetTaggedObject())->GetChangeListener();
387     JSHandle<ChangeListener> listeners(thread, listenersValue.GetTaggedObject());
388     uint32_t holeIndex = ChangeListener::CheckHole(listeners);
389     EXPECT_TRUE(holeIndex == 0U);
390     // new class
391     JSHandle<JSHClass> newClass(thread, Obj2->GetClass());
392     EXPECT_TRUE(newClass->GetObjectSize() < obj2Class->GetObjectSize());
393     EXPECT_EQ(newClass->NumberOfProps(), 0U);
394     EXPECT_TRUE(newClass->IsDictionaryMode());
395     EXPECT_TRUE(newClass->IsPrototype());
396 }
397 
HWTEST_F_L0(JSHClassTest,UpdatePropertyMetaData)398 HWTEST_F_L0(JSHClassTest, UpdatePropertyMetaData)
399 {
400     EcmaVM *vm = thread->GetEcmaVM();
401     ObjectFactory *factory = vm->GetFactory();
402     JSHandle<JSTaggedValue> objKey(factory->NewFromASCII("key0"));
403     PropertyAttributes oldAttr = PropertyAttributes(0);
404     PropertyAttributes newAttr = PropertyAttributes(1);
405     oldAttr.SetIsInlinedProps(true);
406     JSHandle<JSHClass> objClass = CreateJSHClass(thread);
407     JSHandle<JSObject> Obj = factory->NewJSObject(objClass);
408     // Set Transitions
409     ElementsKind oldKind = Obj->GetJSHClass()->GetElementsKind();
410     JSHClass::AddProperty(thread, Obj, objKey, oldAttr);
411     JSObject::TryMigrateToGenericKindForJSObject(thread, Obj, oldKind);
412     // update metaData
413     objClass->UpdatePropertyMetaData(thread, objKey.GetTaggedValue(), newAttr);
414     LayoutInfo *layoutInfo = LayoutInfo::Cast(objClass->GetLayout().GetTaggedObject());
415     EXPECT_EQ(layoutInfo->GetAttr(oldAttr.GetOffset()).GetPropertyMetaData(), newAttr.GetPropertyMetaData());
416 }
417 
HWTEST_F_L0(JSHClassTest,SetPrototype)418 HWTEST_F_L0(JSHClassTest, SetPrototype)
419 {
420     EcmaVM *vm = thread->GetEcmaVM();
421     ObjectFactory *factory = vm->GetFactory();
422     JSHandle<GlobalEnv> env =vm->GetGlobalEnv();
423     JSHandle<JSTaggedValue> nullHandle(thread, JSTaggedValue::Null());
424     JSHandle<JSTaggedValue> objectFuncPrototype = env->GetObjectFunctionPrototype();
425 
426     JSHandle<JSHClass> objectClass = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, nullHandle);
427     EXPECT_EQ(objectClass->GetPrototype(), nullHandle.GetTaggedValue());
428     objectClass->SetPrototype(thread, objectFuncPrototype);
429     EXPECT_EQ(objectClass->GetPrototype(), objectFuncPrototype.GetTaggedValue());
430 }
431 
HWTEST_F_L0(JSHClassTest,ProxyHClassClone)432 HWTEST_F_L0(JSHClassTest, ProxyHClassClone)
433 {
434     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
435 
436     JSHandle<JSFunction> objectFn(thread->GetGlobalEnv()->GetObjectFunction());
437     JSHandle<JSObject> target = factory->NewJSObjectByConstructor(objectFn, JSHandle<JSTaggedValue>(objectFn));
438     JSHandle<JSObject> handler = factory->NewJSObjectByConstructor(objectFn, JSHandle<JSTaggedValue>(objectFn));
439 
440     JSHandle<JSProxy> proxy = JSProxy::ProxyCreate(thread,
441         JSHandle<JSTaggedValue>(target), JSHandle<JSTaggedValue>(handler));
442 
443     JSHandle<JSHClass> hclass(thread, proxy->GetClass());
444     EXPECT_FALSE(hclass->IsJSObject());
445     EXPECT_GT(hclass->GetObjectSize(), 0);
446     EXPECT_EQ(hclass->GetInlinedProperties(), 0);
447 
448     JSHandle<JSHClass> newHClass = JSHClass::Clone(thread, hclass);
449     EXPECT_EQ(newHClass->GetObjectType(), hclass->GetObjectType());
450     EXPECT_EQ(newHClass->GetObjectSize(), hclass->GetObjectSize());
451     EXPECT_EQ(newHClass->GetInlinedPropsStartSize(), hclass->GetInlinedPropsStartSize());
452     EXPECT_EQ(newHClass->GetInlinedProperties(), hclass->GetInlinedProperties());
453     EXPECT_EQ(newHClass->GetLayout(), hclass->GetLayout());
454 }
455 }  // namespace panda::test
456