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