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