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