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