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