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