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 25using namespace panda; 26using namespace panda::ecmascript; 27 28namespace panda::test { 29class JSHClassTest : public BaseTestWithScope<false> { 30}; 31 32HWTEST_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 52HWTEST_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 93HWTEST_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 112HWTEST_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 // withoutInlinedProperties 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 // withoutInlinedProperties is true 131 cloneClass = JSHClass::Clone(thread, objectClass, true); 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 143HWTEST_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 179static 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 188HWTEST_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 223HWTEST_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 251HWTEST_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 285HWTEST_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 321HWTEST_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 356HWTEST_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 402HWTEST_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 422HWTEST_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 436HWTEST_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