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