• 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     objectClass = factory->NewEcmaHClass(EcmaString::SIZE, JSType::STRING, nullHandle);
89     objectSize = objectClass->SizeFromJSHClass(*objectClass);
90     EXPECT_EQ(objectSize, 16U);
91 
92     objectClass = factory->NewEcmaHClass(MachineCode::SIZE, JSType::MACHINE_CODE_OBJECT, nullHandle);
93     objectSize = objectClass->SizeFromJSHClass(*objectClass);
94     EXPECT_EQ(objectSize, 24U);
95     // size is an integral multiple of eight
96     objectClass = factory->NewEcmaHClass(JSObject::SIZE - 1, JSType::JS_OBJECT, nullHandle);
97     objectSize = objectClass->SizeFromJSHClass(*objectClass);
98     EXPECT_EQ(objectSize, 56U);
99 
100     objectClass = factory->NewEcmaHClass(JSObject::SIZE + 1, JSType::JS_OBJECT, nullHandle);
101     objectSize = objectClass->SizeFromJSHClass(*objectClass);
102     EXPECT_EQ(objectSize, 64U);
103 
104     objectClass = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, nullHandle);
105     objectSize = objectClass->SizeFromJSHClass(*objectClass);
106     EXPECT_EQ(objectSize, 64U);
107 }
108 
HWTEST_F_L0(JSHClassTest,HasReferenceField)109 HWTEST_F_L0(JSHClassTest, HasReferenceField)
110 {
111     EcmaVM *vm = thread->GetEcmaVM();
112     ObjectFactory *factory = vm->GetFactory();
113     JSHandle<JSTaggedValue> nullHandle(thread, JSTaggedValue::Null());
114 
115     JSHandle<JSHClass> obj1Class = factory->NewEcmaHClass(TaggedArray::SIZE, JSType::STRING, nullHandle);
116     JSHandle<JSHClass> obj2Class =
117         factory->NewEcmaHClass(TaggedArray::SIZE, JSType::JS_NATIVE_POINTER, nullHandle);
118     JSHandle<JSHClass> obj3Class = factory->NewEcmaHClass(TaggedArray::SIZE, JSType::JS_OBJECT, nullHandle);
119     EXPECT_FALSE(obj1Class->HasReferenceField());
120     EXPECT_FALSE(obj2Class->HasReferenceField());
121     EXPECT_TRUE(obj3Class->HasReferenceField());
122 }
123 
HWTEST_F_L0(JSHClassTest,Clone)124 HWTEST_F_L0(JSHClassTest, Clone)
125 {
126     EcmaVM *vm = thread->GetEcmaVM();
127     ObjectFactory *factory = vm->GetFactory();
128     JSHandle<JSTaggedValue> nullHandle(thread, JSTaggedValue::Null());
129 
130     JSHandle<JSHClass> objectClass = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, nullHandle);
131     // withoutInlinedProperties is false
132     JSHandle<JSHClass> cloneClass = JSHClass::Clone(thread, objectClass, false);
133     EXPECT_TRUE(*cloneClass != nullptr);
134     EXPECT_TRUE(objectClass->GetObjectSize() == cloneClass->GetObjectSize());
135     EXPECT_EQ(cloneClass->GetObjectSize(), 64U); // 64 : 64 not missing the size of inlinedproperties
136     EXPECT_TRUE(objectClass->GetLayout() == cloneClass->GetLayout());
137     EXPECT_EQ(JSTaggedValue::SameValue(objectClass->GetPrototype(), cloneClass->GetPrototype()), true);
138     EXPECT_TRUE(objectClass->GetBitField() == cloneClass->GetBitField());
139     EXPECT_TRUE(objectClass->GetBitField1() == cloneClass->GetBitField1());
140     EXPECT_TRUE(objectClass->NumberOfProps() == cloneClass->NumberOfProps());
141     EXPECT_EQ(cloneClass->GetNextInlinedPropsIndex(), 0); // 0 : 0 mean index
142     // withoutInlinedProperties is true
143     cloneClass = JSHClass::Clone(thread, objectClass, true);
144     EXPECT_TRUE(*cloneClass != nullptr);
145     EXPECT_TRUE(objectClass->GetObjectSize() > cloneClass->GetObjectSize());
146     EXPECT_EQ(cloneClass->GetObjectSize(), 32U); // 32 : 32 missing the size of inlinedproperties
147     EXPECT_TRUE(objectClass->GetLayout() == cloneClass->GetLayout());
148     EXPECT_EQ(JSTaggedValue::SameValue(objectClass->GetPrototype(), cloneClass->GetPrototype()), true);
149     EXPECT_TRUE(objectClass->GetBitField() == cloneClass->GetBitField());
150     EXPECT_TRUE(objectClass->GetBitField1() > cloneClass->GetBitField1());
151     EXPECT_TRUE(objectClass->NumberOfProps() == cloneClass->NumberOfProps());
152     EXPECT_EQ(cloneClass->GetNextNonInlinedPropsIndex(), 0); // 0 : 0 mean index
153 }
154 
HWTEST_F_L0(JSHClassTest,TransitionElementsToDictionary)155 HWTEST_F_L0(JSHClassTest, TransitionElementsToDictionary)
156 {
157     EcmaVM *vm = thread->GetEcmaVM();
158     ObjectFactory *factory = vm->GetFactory();
159 
160     JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
161     JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
162     JSHandle<JSObject> jsObject = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
163     JSHandle<JSHClass> objectClass(thread, jsObject->GetJSHClass());
164     JSHandle<JSTaggedValue> objKey1(factory->NewFromASCII("key1"));
165     JSHandle<JSTaggedValue> objKey2(factory->NewFromASCII("key2"));
166     JSHandle<JSTaggedValue> objKey3(factory->NewFromASCII("key3"));
167 
168     JSHandle<JSTaggedValue> objValue1(thread, JSTaggedValue(1));
169     JSHandle<JSTaggedValue> objValue2(thread, JSTaggedValue(2));
170     JSHandle<JSTaggedValue> objValue3(thread, JSTaggedValue(3));
171 
172     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(jsObject), objKey1, objValue1);
173     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(jsObject), objKey2, objValue2);
174     JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(jsObject), objKey3, objValue3);
175     // class is not dictionary mode
176     EXPECT_FALSE(jsObject->GetJSHClass()->IsDictionaryMode());
177     JSHClass::TransitionElementsToDictionary(thread, jsObject);
178     auto resultDict = NameDictionary::Cast(jsObject->GetProperties().GetTaggedObject());
179     EXPECT_TRUE(resultDict != nullptr);
180     EXPECT_EQ(resultDict->EntriesCount(), 3); // 3 : 3 entry
181 
182     JSHandle<JSHClass> dictionaryClass(thread, jsObject->GetJSHClass());
183     EXPECT_TRUE(dictionaryClass->IsDictionaryMode());
184     EXPECT_EQ(dictionaryClass->GetObjectSize() + 32U, objectClass->GetObjectSize());
185     EXPECT_TRUE(dictionaryClass->IsDictionaryElement());
186     EXPECT_FALSE(dictionaryClass->IsStableElements());
187 }
188 
CreateJSHClass(JSThread * thread)189 static JSHandle<JSHClass> CreateJSHClass(JSThread *thread)
190 {
191     JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
192     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
193     JSHandle<JSTaggedValue> objectFuncPrototype = env->GetObjectFunctionPrototype();
194     JSHandle<JSHClass> hclass = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, objectFuncPrototype);
195     return hclass;
196 }
197 
HWTEST_F_L0(JSHClassTest,SetPropertyOfObjHClass_001)198 HWTEST_F_L0(JSHClassTest, SetPropertyOfObjHClass_001)
199 {
200     EcmaVM *vm = thread->GetEcmaVM();
201     ObjectFactory *factory = vm->GetFactory();
202     JSHandle<JSTaggedValue> accessorData(factory->NewAccessorData());
203     JSHandle<EcmaString> keyHandle = factory->NewFromASCII("key");
204     JSHandle<JSTaggedValue> keyHandle0(factory->NewFromASCII("key0"));
205     JSHandle<JSTaggedValue> keyHandle2(factory->NewFromASCII("key2"));
206     JSHandle<JSTaggedValue> keyHandle4(factory->NewFromASCII("key4"));
207     // empty layoutInfo
208     JSHandle<JSHClass> parentsClass = CreateJSHClass(thread);
209 
210     uint32_t length = 6;
211     JSHandle<TaggedArray> properties = factory->NewTaggedArray(length);
212     for (int i = 0; i < static_cast<int>(length); i++) {
213         if (i % 2 == 0) {
214             JSHandle<JSTaggedValue> newValue(thread, JSTaggedValue(i));
215             JSHandle<EcmaString> newKey =
216                 factory->ConcatFromString(keyHandle, JSTaggedValue::ToString(thread, newValue));
217             properties->Set(thread, i, newKey.GetTaggedValue());
218             continue;
219         }
220         properties->Set(thread, i, accessorData.GetTaggedValue());
221     }
222     JSHandle<JSHClass> childClass = factory->SetLayoutInObjHClass(properties, 3, parentsClass);
223     JSHandle<JSObject> childObj = factory->NewJSObject(childClass);
224 
225     std::vector<JSTaggedValue> keyVector;
226     JSObject::GetAllKeys(childObj, keyVector);
227     EXPECT_EQ(keyVector.size(), 3U);
228     EXPECT_TRUE(JSObject::HasProperty(thread, childObj, keyHandle0));
229     EXPECT_TRUE(JSObject::HasProperty(thread, childObj, keyHandle2));
230     EXPECT_TRUE(JSObject::HasProperty(thread, childObj, keyHandle4));
231 }
232 
HWTEST_F_L0(JSHClassTest,SetPropertyOfObjHClass_002)233 HWTEST_F_L0(JSHClassTest, SetPropertyOfObjHClass_002)
234 {
235     EcmaVM *vm = thread->GetEcmaVM();
236     ObjectFactory *factory = vm->GetFactory();
237     JSHandle<JSHClass> objClass = CreateJSHClass(thread);
238     JSHandle<JSObject> Obj1 = factory->NewJSObject(objClass);
239     JSHandle<JSObject> Obj2 = factory->NewJSObject(objClass);
240     PropertyAttributes attr = PropertyAttributes::Default();
241 
242     JSHandle<JSTaggedValue> keyE(factory->NewFromASCII("e"));
243     JSHandle<JSTaggedValue> keyF(factory->NewFromASCII("f"));
244     // not empty layoutInfo
245     JSObject::SetProperty(thread, Obj1, keyE, JSHandle<JSTaggedValue>(thread, JSTaggedValue(7)));
246     JSObject::SetProperty(thread, Obj2, keyF, JSHandle<JSTaggedValue>(thread, JSTaggedValue(8)));
247 
248     JSHandle<JSHClass> propertyHclass = JSHClass::SetPropertyOfObjHClass(thread, objClass, keyE, attr);
249     JSHandle<JSHClass> obj1Class(thread, Obj1->GetClass());
250     EXPECT_TRUE(propertyHclass == obj1Class);
251 
252     propertyHclass = JSHClass::SetPropertyOfObjHClass(thread, objClass, keyF, attr);
253     JSHandle<JSHClass> obj2Class(thread, Obj2->GetClass());
254     EXPECT_TRUE(propertyHclass == obj2Class);
255 }
256 
HWTEST_F_L0(JSHClassTest,AddProperty)257 HWTEST_F_L0(JSHClassTest, AddProperty)
258 {
259     EcmaVM *vm = thread->GetEcmaVM();
260     ObjectFactory *factory = vm->GetFactory();
261     JSHandle<EcmaString> keyHandle = factory->NewFromASCII("key");
262     JSHandle<JSTaggedValue> keyHandle0(factory->NewFromASCII("key0"));
263     JSHandle<JSTaggedValue> keyHandle1(factory->NewFromASCII("key1"));
264     JSHandle<JSTaggedValue> keyHandle2(factory->NewFromASCII("key2"));
265     PropertyAttributes attr = PropertyAttributes::Default();
266     attr.SetIsInlinedProps(true);
267     // empty layoutInfo
268     JSHandle<JSHClass> objClass1 = CreateJSHClass(thread);
269     JSHandle<JSObject> Obj = factory->NewJSObject(objClass1);
270     JSHandle<JSHClass> objClass(thread, Obj->GetClass());
271     EXPECT_FALSE(objClass1 != objClass);
272     int keyLength = 3;
273     for (int i = 0; i <keyLength; i++) {
274         JSHandle<JSTaggedValue> keyValue(thread, JSTaggedValue(i));
275         JSHandle<JSTaggedValue> keyHandleI(
276             factory->ConcatFromString(keyHandle, JSTaggedValue::ToString(thread, keyValue)));
277         attr.SetOffset(i);
278         JSHClass::AddProperty(thread, Obj, keyHandleI, attr);
279     }
280     EXPECT_TRUE(objClass1 == objClass);
281     std::vector<JSTaggedValue> keyVector;
282     JSObject::GetAllKeys(Obj, keyVector);
283     EXPECT_EQ(keyVector.size(), 3U);
284     EXPECT_TRUE(JSObject::HasProperty(thread, Obj, keyHandle0));
285     EXPECT_TRUE(JSObject::HasProperty(thread, Obj, keyHandle1));
286     EXPECT_TRUE(JSObject::HasProperty(thread, Obj, keyHandle2));
287 }
288 
HWTEST_F_L0(JSHClassTest,TransitionExtension)289 HWTEST_F_L0(JSHClassTest, TransitionExtension)
290 {
291     EcmaVM *vm = thread->GetEcmaVM();
292     ObjectFactory *factory = vm->GetFactory();
293     JSHandle<JSTaggedValue> preExtensionsKey = thread->GlobalConstants()->GetHandledPreventExtensionsString();
294     JSHandle<JSTaggedValue> keyHandle0(factory->NewFromASCII("key0"));
295     JSHandle<JSTaggedValue> keyHandle1(factory->NewFromASCII("key1"));
296     JSHandle<JSTaggedValue> keyHandle2(factory->NewFromASCII("key2"));
297     PropertyAttributes attr = PropertyAttributes(0);
298     attr.SetIsInlinedProps(true);
299     JSHandle<JSHClass> obj1Class = CreateJSHClass(thread);
300     JSHandle<JSHClass> obj2Class = CreateJSHClass(thread);
301     obj2Class->SetExtensible(true);
302     JSHandle<JSObject> Obj1 = factory->NewJSObject(obj1Class);
303     JSHandle<JSObject> Obj2 = factory->NewJSObject(obj2Class);
304     JSObject::SetProperty(thread, Obj2, keyHandle0, JSHandle<JSTaggedValue>(thread, JSTaggedValue(7)));
305     JSObject::SetProperty(thread, Obj2, keyHandle1, JSHandle<JSTaggedValue>(thread, JSTaggedValue(8)));
306     JSObject::SetProperty(thread, Obj2, keyHandle2, JSHandle<JSTaggedValue>(thread, JSTaggedValue(9)));
307     // obj has key "PreventExtensions"
308     JSHClass::AddProperty(thread, Obj1, preExtensionsKey, attr);
309     JSHandle<JSHClass> newClass1 = JSHClass::TransitionExtension(thread, obj1Class);
310     JSHandle<JSHClass> objClass(thread, Obj1->GetClass());
311     EXPECT_TRUE(newClass1 == objClass);
312     // obj has no key "PreventExtensions"
313     JSHandle<JSHClass> newClass2 = JSHClass::TransitionExtension(thread, obj2Class);
314     EXPECT_FALSE(newClass2->IsExtensible());
315     JSHandle<TransitionsDictionary> dictionary(thread, obj2Class->GetTransitions());
316     // find key
317     std::vector<JSTaggedValue> keyVector;
318     dictionary->GetAllKeysIntoVector(keyVector);
319     EXPECT_EQ(keyVector[0], keyHandle0.GetTaggedValue());
320     EXPECT_EQ(keyVector[1], preExtensionsKey.GetTaggedValue());
321 }
322 
HWTEST_F_L0(JSHClassTest,TransitionProto)323 HWTEST_F_L0(JSHClassTest, TransitionProto)
324 {
325     EcmaVM *vm = thread->GetEcmaVM();
326     ObjectFactory *factory = vm->GetFactory();
327     JSHandle<GlobalEnv> env =vm->GetGlobalEnv();
328     JSHandle<JSTaggedValue> funcPrototype = env->GetFunctionPrototype();
329     JSHandle<JSTaggedValue> prototypeKey = thread->GlobalConstants()->GetHandledPrototypeString();
330     JSHandle<JSTaggedValue> obj1Key(factory->NewFromASCII("key0"));
331     JSHandle<JSTaggedValue> obj2Key(factory->NewFromASCII("key1"));
332     JSHandle<JSTaggedValue> obj3Key(factory->NewFromASCII("key2"));
333     PropertyAttributes attr = PropertyAttributes(0);
334     attr.SetIsInlinedProps(true);
335     JSHandle<JSHClass> objClass = CreateJSHClass(thread);
336     JSHandle<JSObject> Obj = factory->NewJSObject(objClass);
337     // obj has no key "prototype"
338     JSHClass::AddProperty(thread, Obj, obj1Key, attr);
339     JSHClass::AddProperty(thread, Obj, obj2Key, attr);
340     JSHClass::AddProperty(thread, Obj, obj3Key, attr);
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     JSHClass::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     JSHClass::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     JSHClass::AddProperty(thread, Obj, objKey, oldAttr);
410     // update metaData
411     objClass->UpdatePropertyMetaData(thread, objKey.GetTaggedValue(), newAttr);
412     LayoutInfo *layoutInfo = LayoutInfo::Cast(objClass->GetLayout().GetTaggedObject());
413     EXPECT_EQ(layoutInfo->GetAttr(oldAttr.GetOffset()).GetPropertyMetaData(), newAttr.GetPropertyMetaData());
414 }
415 
HWTEST_F_L0(JSHClassTest,SetPrototype)416 HWTEST_F_L0(JSHClassTest, SetPrototype)
417 {
418     EcmaVM *vm = thread->GetEcmaVM();
419     ObjectFactory *factory = vm->GetFactory();
420     JSHandle<GlobalEnv> env =vm->GetGlobalEnv();
421     JSHandle<JSTaggedValue> nullHandle(thread, JSTaggedValue::Null());
422     JSHandle<JSTaggedValue> objectFuncPrototype = env->GetObjectFunctionPrototype();
423 
424     JSHandle<JSHClass> objectClass = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, nullHandle);
425     EXPECT_EQ(objectClass->GetPrototype(), nullHandle.GetTaggedValue());
426     objectClass->SetPrototype(thread, objectFuncPrototype);
427     EXPECT_EQ(objectClass->GetPrototype(), objectFuncPrototype.GetTaggedValue());
428 }
429 }  // namespace panda::test