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