14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#include "ecmascript/ecma_vm.h" 174514f5e3Sopenharmony_ci#include "ecmascript/js_symbol.h" 184514f5e3Sopenharmony_ci#include "ecmascript/object_factory.h" 194514f5e3Sopenharmony_ci#include "ecmascript/property_attributes.h" 204514f5e3Sopenharmony_ci#include "ecmascript/tagged_hash_table.h" 214514f5e3Sopenharmony_ci#include "ecmascript/tests/test_helper.h" 224514f5e3Sopenharmony_ci#include "ecmascript/transitions_dictionary.h" 234514f5e3Sopenharmony_ci 244514f5e3Sopenharmony_ciusing namespace panda::ecmascript; 254514f5e3Sopenharmony_ci 264514f5e3Sopenharmony_cinamespace panda::test { 274514f5e3Sopenharmony_ciclass TransitionsDictionaryTest : public BaseTestWithScope<false> { 284514f5e3Sopenharmony_ci}; 294514f5e3Sopenharmony_ci 304514f5e3Sopenharmony_ciHWTEST_F_L0(TransitionsDictionaryTest, IsMatch) 314514f5e3Sopenharmony_ci{ 324514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> key(thread, JSTaggedValue::True()); 334514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> otherKey(thread, JSTaggedValue::False()); 344514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined()); 354514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> otherDetails(thread, JSTaggedValue::Null()); 364514f5e3Sopenharmony_ci bool result = TransitionsDictionary::IsMatch(key.GetTaggedValue(), metaData.GetTaggedValue(), 374514f5e3Sopenharmony_ci otherKey.GetTaggedValue(), otherDetails.GetTaggedValue()); 384514f5e3Sopenharmony_ci EXPECT_FALSE(result); 394514f5e3Sopenharmony_ci 404514f5e3Sopenharmony_ci result = TransitionsDictionary::IsMatch(key.GetTaggedValue(), metaData.GetTaggedValue(), 414514f5e3Sopenharmony_ci key.GetTaggedValue(), metaData.GetTaggedValue()); 424514f5e3Sopenharmony_ci EXPECT_TRUE(result); 434514f5e3Sopenharmony_ci} 444514f5e3Sopenharmony_ci 454514f5e3Sopenharmony_ciHWTEST_F_L0(TransitionsDictionaryTest, Hash) 464514f5e3Sopenharmony_ci{ 474514f5e3Sopenharmony_ci auto vm = thread->GetEcmaVM(); 484514f5e3Sopenharmony_ci auto factory = vm->GetFactory(); 494514f5e3Sopenharmony_ci 504514f5e3Sopenharmony_ci // test when key is string. 514514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> key1(factory->NewFromStdString("k")); 524514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> metaData1(thread, JSTaggedValue(1)); // test metaData : 1 534514f5e3Sopenharmony_ci int hash = TransitionsDictionary::Hash(key1.GetTaggedValue(), metaData1.GetTaggedValue()); 544514f5e3Sopenharmony_ci // "k" : 107, hashSeed : 0, shift : 5, metaData : 1 554514f5e3Sopenharmony_ci EXPECT_EQ(hash, 108); // 108 : (0 << 5) - 0 + 107 + 1 564514f5e3Sopenharmony_ci 574514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> key2(factory->NewFromStdString("key")); 584514f5e3Sopenharmony_ci hash = TransitionsDictionary::Hash(key2.GetTaggedValue(), metaData1.GetTaggedValue()); 594514f5e3Sopenharmony_ci EXPECT_EQ(hash, 106080); 604514f5e3Sopenharmony_ci 614514f5e3Sopenharmony_ci // test when key is symbol. 624514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> symbolName(factory->NewFromStdString("s")); 634514f5e3Sopenharmony_ci JSHandle<JSSymbol> privateNameSymbol = factory->NewPrivateNameSymbol(symbolName); 644514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> symbolValue = JSHandle<JSTaggedValue>::Cast(privateNameSymbol); 654514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> metaData2(thread, JSTaggedValue(2)); // test metaData : 2 664514f5e3Sopenharmony_ci hash = TransitionsDictionary::Hash(symbolValue.GetTaggedValue(), metaData2.GetTaggedValue()); 674514f5e3Sopenharmony_ci EXPECT_EQ(hash, 117); // 117 : 115 + 2 684514f5e3Sopenharmony_ci} 694514f5e3Sopenharmony_ci 704514f5e3Sopenharmony_ciHWTEST_F_L0(TransitionsDictionaryTest, GetKeyIndex) 714514f5e3Sopenharmony_ci{ 724514f5e3Sopenharmony_ci int entry = 10; 734514f5e3Sopenharmony_ci EXPECT_EQ(TransitionsDictionary::GetKeyIndex(entry), 33); // 33 : 3 + 10 * 3 + 0 744514f5e3Sopenharmony_ci} 754514f5e3Sopenharmony_ci 764514f5e3Sopenharmony_ciHWTEST_F_L0(TransitionsDictionaryTest, GetValueIndex) 774514f5e3Sopenharmony_ci{ 784514f5e3Sopenharmony_ci int entry = 10; 794514f5e3Sopenharmony_ci EXPECT_EQ(TransitionsDictionary::GetValueIndex(entry), 34); // 34 : 3 + 10 * 3 + 1 804514f5e3Sopenharmony_ci} 814514f5e3Sopenharmony_ci 824514f5e3Sopenharmony_ciHWTEST_F_L0(TransitionsDictionaryTest, GetEntryIndex) 834514f5e3Sopenharmony_ci{ 844514f5e3Sopenharmony_ci int entry = 10; 854514f5e3Sopenharmony_ci EXPECT_EQ(TransitionsDictionary::GetEntryIndex(entry), 33); // 33 : 3 + 10 * 3 864514f5e3Sopenharmony_ci} 874514f5e3Sopenharmony_ci 884514f5e3Sopenharmony_ciHWTEST_F_L0(TransitionsDictionaryTest, Create) 894514f5e3Sopenharmony_ci{ 904514f5e3Sopenharmony_ci int numberOfElements = 8; 914514f5e3Sopenharmony_ci JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements); 924514f5e3Sopenharmony_ci EXPECT_EQ(transDic->GetLength(), 27U); // 27 : 3 + 8 * 3 934514f5e3Sopenharmony_ci EXPECT_EQ(transDic->EntriesCount(), 0); 944514f5e3Sopenharmony_ci EXPECT_EQ(transDic->HoleEntriesCount(), 0); 954514f5e3Sopenharmony_ci} 964514f5e3Sopenharmony_ci 974514f5e3Sopenharmony_ciHWTEST_F_L0(TransitionsDictionaryTest, Shrink) 984514f5e3Sopenharmony_ci{ 994514f5e3Sopenharmony_ci auto vm = thread->GetEcmaVM(); 1004514f5e3Sopenharmony_ci auto factory = vm->GetFactory(); 1014514f5e3Sopenharmony_ci int numberOfElements = 64; 1024514f5e3Sopenharmony_ci JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements); 1034514f5e3Sopenharmony_ci EXPECT_EQ(transDic->GetLength(), 195U); // 195 : 3 + 64 * 3 1044514f5e3Sopenharmony_ci EXPECT_EQ(transDic->EntriesCount(), 0); 1054514f5e3Sopenharmony_ci 1064514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined()); 1074514f5e3Sopenharmony_ci int eleNum = 7; 1084514f5e3Sopenharmony_ci for (int index = 0; index < eleNum; index++) { 1094514f5e3Sopenharmony_ci std::string keyStr = "key" + std::to_string(index); 1104514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> key(factory->NewFromStdString(keyStr)); 1114514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> value(factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT)); 1124514f5e3Sopenharmony_ci TransitionsDictionary::PutIfAbsent(thread, transDic, key, value, metaData); 1134514f5e3Sopenharmony_ci } 1144514f5e3Sopenharmony_ci JSHandle<TransitionsDictionary> transDicAfterShink = TransitionsDictionary::Shrink(thread, transDic); 1154514f5e3Sopenharmony_ci EXPECT_EQ(transDicAfterShink->GetLength(), 51U); // (1 << (32 - Clz((7 + (7 >> 1)) - 1))) * 3 + 3 1164514f5e3Sopenharmony_ci EXPECT_EQ(transDic->EntriesCount(), eleNum); 1174514f5e3Sopenharmony_ci} 1184514f5e3Sopenharmony_ci 1194514f5e3Sopenharmony_ciHWTEST_F_L0(TransitionsDictionaryTest, Get_Set_Attributes) 1204514f5e3Sopenharmony_ci{ 1214514f5e3Sopenharmony_ci int numberOfElements = 8; 1224514f5e3Sopenharmony_ci JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements); 1234514f5e3Sopenharmony_ci uint32_t length = transDic->GetLength(); 1244514f5e3Sopenharmony_ci EXPECT_EQ(length, 27U); // 27 : 3 + 8 * 3 1254514f5e3Sopenharmony_ci 1264514f5e3Sopenharmony_ci for (int index = 0; index < numberOfElements; index++) { 1274514f5e3Sopenharmony_ci transDic->SetAttributes(thread, index, JSTaggedValue(index)); 1284514f5e3Sopenharmony_ci JSTaggedValue value = transDic->GetAttributes(index); 1294514f5e3Sopenharmony_ci EXPECT_EQ(value, JSTaggedValue(index)); 1304514f5e3Sopenharmony_ci } 1314514f5e3Sopenharmony_ci} 1324514f5e3Sopenharmony_ci 1334514f5e3Sopenharmony_ciusing TestCommonCB = std::function<void(JSThread *, int index, 1344514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> &, JSHandle<JSTaggedValue> &)>; 1354514f5e3Sopenharmony_civoid TestCommon(JSThread *thread, int numberOfElements, TestCommonCB cb) 1364514f5e3Sopenharmony_ci{ 1374514f5e3Sopenharmony_ci auto factory = thread->GetEcmaVM()->GetFactory(); 1384514f5e3Sopenharmony_ci 1394514f5e3Sopenharmony_ci for (int index = 0; index < numberOfElements; index++) { 1404514f5e3Sopenharmony_ci std::string keyStr = "key" + std::to_string(index); 1414514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> key(factory->NewFromStdString(keyStr)); 1424514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> value(factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT)); 1434514f5e3Sopenharmony_ci cb(thread, index, key, value); 1444514f5e3Sopenharmony_ci } 1454514f5e3Sopenharmony_ci} 1464514f5e3Sopenharmony_ci 1474514f5e3Sopenharmony_ciHWTEST_F_L0(TransitionsDictionaryTest, SetEntry) 1484514f5e3Sopenharmony_ci{ 1494514f5e3Sopenharmony_ci int numberOfElements = 8; 1504514f5e3Sopenharmony_ci JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements); 1514514f5e3Sopenharmony_ci 1524514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined()); 1534514f5e3Sopenharmony_ci TestCommon(thread, numberOfElements, 1544514f5e3Sopenharmony_ci [&](JSThread *thread, int index, JSHandle<JSTaggedValue> &key, JSHandle<JSTaggedValue> &value) { 1554514f5e3Sopenharmony_ci transDic->SetEntry(thread, index, key.GetTaggedValue(), value.GetTaggedValue(), 1564514f5e3Sopenharmony_ci metaData.GetTaggedValue()); 1574514f5e3Sopenharmony_ci EXPECT_EQ(transDic->GetKey(index), key.GetTaggedValue()); 1584514f5e3Sopenharmony_ci }); 1594514f5e3Sopenharmony_ci} 1604514f5e3Sopenharmony_ci 1614514f5e3Sopenharmony_ciHWTEST_F_L0(TransitionsDictionaryTest, FindEntry) 1624514f5e3Sopenharmony_ci{ 1634514f5e3Sopenharmony_ci int numberOfElements = 8; 1644514f5e3Sopenharmony_ci JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements); 1654514f5e3Sopenharmony_ci 1664514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined()); 1674514f5e3Sopenharmony_ci TestCommon(thread, numberOfElements, 1684514f5e3Sopenharmony_ci [&](JSThread *thread, int index, JSHandle<JSTaggedValue> &key, JSHandle<JSTaggedValue> &value) { 1694514f5e3Sopenharmony_ci transDic = TransitionsDictionary::PutIfAbsent(thread, transDic, key, value, metaData); 1704514f5e3Sopenharmony_ci int foundEntry = transDic->FindEntry(key.GetTaggedValue(), metaData.GetTaggedValue()); 1714514f5e3Sopenharmony_ci EXPECT_EQ(index + 3, foundEntry); // 3 : table header size 1724514f5e3Sopenharmony_ci }); 1734514f5e3Sopenharmony_ci} 1744514f5e3Sopenharmony_ci 1754514f5e3Sopenharmony_ciHWTEST_F_L0(TransitionsDictionaryTest, RemoveElement) 1764514f5e3Sopenharmony_ci{ 1774514f5e3Sopenharmony_ci int numberOfElements = 8; 1784514f5e3Sopenharmony_ci JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements); 1794514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined()); 1804514f5e3Sopenharmony_ci TestCommon(thread, numberOfElements, 1814514f5e3Sopenharmony_ci [&](JSThread *thread, int index, JSHandle<JSTaggedValue> &key, JSHandle<JSTaggedValue> &value) { 1824514f5e3Sopenharmony_ci transDic = TransitionsDictionary::PutIfAbsent(thread, transDic, key, value, metaData); 1834514f5e3Sopenharmony_ci }); 1844514f5e3Sopenharmony_ci auto factory = thread->GetEcmaVM()->GetFactory(); 1854514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> key7(factory->NewFromStdString("key7")); // test remove element by "key7" 1864514f5e3Sopenharmony_ci int foundEntry = transDic->FindEntry(key7.GetTaggedValue(), metaData.GetTaggedValue()); 1874514f5e3Sopenharmony_ci EXPECT_EQ(foundEntry, 7 + 3); 1884514f5e3Sopenharmony_ci EXPECT_EQ(transDic->EntriesCount(), 8); 1894514f5e3Sopenharmony_ci 1904514f5e3Sopenharmony_ci transDic->RemoveElement(thread, foundEntry); 1914514f5e3Sopenharmony_ci foundEntry = transDic->FindEntry(key7.GetTaggedValue(), metaData.GetTaggedValue()); 1924514f5e3Sopenharmony_ci EXPECT_EQ(foundEntry, -1); // -1 : not found entry 1934514f5e3Sopenharmony_ci EXPECT_EQ(transDic->EntriesCount(), 7); 1944514f5e3Sopenharmony_ci} 1954514f5e3Sopenharmony_ci 1964514f5e3Sopenharmony_ciHWTEST_F_L0(TransitionsDictionaryTest, PutIfAbsent) 1974514f5e3Sopenharmony_ci{ 1984514f5e3Sopenharmony_ci auto vm = thread->GetEcmaVM(); 1994514f5e3Sopenharmony_ci auto factory = vm->GetFactory(); 2004514f5e3Sopenharmony_ci int numberOfElements = 8; 2014514f5e3Sopenharmony_ci JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements); 2024514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined()); 2034514f5e3Sopenharmony_ci vm->SetEnableForceGC(false); 2044514f5e3Sopenharmony_ci for (int index = 0; index < numberOfElements; index++) { 2054514f5e3Sopenharmony_ci std::string keyStr = "key" + std::to_string(index); 2064514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> key(factory->NewFromStdString(keyStr)); 2074514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> value(factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT)); 2084514f5e3Sopenharmony_ci transDic = TransitionsDictionary::PutIfAbsent(thread, transDic, key, value, metaData); 2094514f5e3Sopenharmony_ci int foundEntry = transDic->FindEntry(key.GetTaggedValue(), metaData.GetTaggedValue()); 2104514f5e3Sopenharmony_ci EXPECT_EQ(foundEntry, index + 3); 2114514f5e3Sopenharmony_ci 2124514f5e3Sopenharmony_ci JSTaggedValue foundValue = transDic->GetValue(foundEntry); 2134514f5e3Sopenharmony_ci JSTaggedValue weakValue = value->CreateAndGetWeakRef(); 2144514f5e3Sopenharmony_ci EXPECT_EQ(foundValue, weakValue); 2154514f5e3Sopenharmony_ci } 2164514f5e3Sopenharmony_ci vm->SetEnableForceGC(true); 2174514f5e3Sopenharmony_ci} 2184514f5e3Sopenharmony_ci 2194514f5e3Sopenharmony_ciHWTEST_F_L0(TransitionsDictionaryTest, Remove) 2204514f5e3Sopenharmony_ci{ 2214514f5e3Sopenharmony_ci int numberOfElements = 64; 2224514f5e3Sopenharmony_ci int eleNum = 7; 2234514f5e3Sopenharmony_ci JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements); 2244514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined()); 2254514f5e3Sopenharmony_ci TestCommon(thread, eleNum, 2264514f5e3Sopenharmony_ci [&](JSThread *thread, int index, JSHandle<JSTaggedValue> &key, JSHandle<JSTaggedValue> &value) { 2274514f5e3Sopenharmony_ci transDic = TransitionsDictionary::PutIfAbsent(thread, transDic, key, value, metaData); 2284514f5e3Sopenharmony_ci }); 2294514f5e3Sopenharmony_ci auto factory = thread->GetEcmaVM()->GetFactory(); 2304514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> key6(factory->NewFromStdString("key6")); // test remove element by "key6" 2314514f5e3Sopenharmony_ci EXPECT_EQ(transDic->EntriesCount(), 7); 2324514f5e3Sopenharmony_ci EXPECT_EQ(transDic->GetLength(), 195U); // 195 : 3 + 64 * 3 2334514f5e3Sopenharmony_ci 2344514f5e3Sopenharmony_ci transDic = TransitionsDictionary::Remove(thread, transDic, key6, metaData.GetTaggedValue()); 2354514f5e3Sopenharmony_ci EXPECT_EQ(transDic->EntriesCount(), 6); // 6 : 7 - 1 2364514f5e3Sopenharmony_ci EXPECT_EQ(transDic->GetLength(), 51U); // (1 << (32 - Clz((6 + (6 >> 1)) - 1))) * 3 + 3 2374514f5e3Sopenharmony_ci} 2384514f5e3Sopenharmony_ci 2394514f5e3Sopenharmony_ciHWTEST_F_L0(TransitionsDictionaryTest, Rehash) 2404514f5e3Sopenharmony_ci{ 2414514f5e3Sopenharmony_ci int numberOfElements = 64; 2424514f5e3Sopenharmony_ci int eleNum = 7; 2434514f5e3Sopenharmony_ci JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements); 2444514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined()); 2454514f5e3Sopenharmony_ci TestCommon(thread, eleNum, 2464514f5e3Sopenharmony_ci [&](JSThread *thread, int index, JSHandle<JSTaggedValue> &key, JSHandle<JSTaggedValue> &value) { 2474514f5e3Sopenharmony_ci transDic = TransitionsDictionary::PutIfAbsent(thread, transDic, key, value, metaData); 2484514f5e3Sopenharmony_ci }); 2494514f5e3Sopenharmony_ci EXPECT_EQ(transDic->HoleEntriesCount(), 0); 2504514f5e3Sopenharmony_ci 2514514f5e3Sopenharmony_ci int lastEntry = 7 + 3; 2524514f5e3Sopenharmony_ci transDic->RemoveElement(thread, lastEntry); // remove one element 2534514f5e3Sopenharmony_ci EXPECT_EQ(transDic->HoleEntriesCount(), 1); 2544514f5e3Sopenharmony_ci 2554514f5e3Sopenharmony_ci transDic->Rehash(thread, *transDic); 2564514f5e3Sopenharmony_ci EXPECT_EQ(transDic->HoleEntriesCount(), 0); 2574514f5e3Sopenharmony_ci} 2584514f5e3Sopenharmony_ci} // namespace panda::test