• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/ecma_vm.h"
17 #include "ecmascript/js_symbol.h"
18 #include "ecmascript/object_factory.h"
19 #include "ecmascript/property_attributes.h"
20 #include "ecmascript/tagged_hash_table.h"
21 #include "ecmascript/tests/test_helper.h"
22 #include "ecmascript/transitions_dictionary.h"
23 
24 using namespace panda::ecmascript;
25 
26 namespace panda::test {
27 class TransitionsDictionaryTest : public testing::Test {
28 public:
SetUpTestCase()29     static void SetUpTestCase()
30     {
31         GTEST_LOG_(INFO) << "SetUpTestCase";
32     }
33 
TearDownTestCase()34     static void TearDownTestCase()
35     {
36         GTEST_LOG_(INFO) << "TearDownCase";
37     }
38 
SetUp()39     void SetUp() override
40     {
41         TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
42     }
43 
TearDown()44     void TearDown() override
45     {
46         TestHelper::DestroyEcmaVMWithScope(instance, scope);
47     }
48 
49     EcmaVM *instance {nullptr};
50     EcmaHandleScope *scope {nullptr};
51     JSThread *thread {nullptr};
52 };
53 
HWTEST_F_L0(TransitionsDictionaryTest,IsMatch)54 HWTEST_F_L0(TransitionsDictionaryTest, IsMatch)
55 {
56     JSHandle<JSTaggedValue> key(thread, JSTaggedValue::True());
57     JSHandle<JSTaggedValue> otherKey(thread, JSTaggedValue::False());
58     JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined());
59     JSHandle<JSTaggedValue> otherDetails(thread, JSTaggedValue::Null());
60     bool result = TransitionsDictionary::IsMatch(key.GetTaggedValue(), metaData.GetTaggedValue(),
61         otherKey.GetTaggedValue(), otherDetails.GetTaggedValue());
62     EXPECT_FALSE(result);
63 
64     result = TransitionsDictionary::IsMatch(key.GetTaggedValue(), metaData.GetTaggedValue(),
65         key.GetTaggedValue(), metaData.GetTaggedValue());
66     EXPECT_TRUE(result);
67 }
68 
HWTEST_F_L0(TransitionsDictionaryTest,Hash)69 HWTEST_F_L0(TransitionsDictionaryTest, Hash)
70 {
71     auto vm = thread->GetEcmaVM();
72     auto factory = vm->GetFactory();
73 
74     // test when key is string.
75     JSHandle<JSTaggedValue> key1(factory->NewFromStdString("k"));
76     JSHandle<JSTaggedValue> metaData1(thread, JSTaggedValue(1)); // test metaData : 1
77     int hash = TransitionsDictionary::Hash(key1.GetTaggedValue(), metaData1.GetTaggedValue());
78     // "k" : 107, hashSeed : 0, shift : 5, metaData : 1
79     EXPECT_EQ(hash, 108); // 108 : (0 << 5) - 0 + 107 + 1
80 
81     JSHandle<JSTaggedValue> key2(factory->NewFromStdString("key"));
82     hash = TransitionsDictionary::Hash(key2.GetTaggedValue(), metaData1.GetTaggedValue());
83     EXPECT_EQ(hash, 106080);
84 
85     // test when key is symbol.
86     JSHandle<JSTaggedValue> symbolName(factory->NewFromStdString("s"));
87     JSHandle<JSSymbol> privateNameSymbol = factory->NewPrivateNameSymbol(symbolName);
88     JSHandle<JSTaggedValue> symbolValue = JSHandle<JSTaggedValue>::Cast(privateNameSymbol);
89     JSHandle<JSTaggedValue> metaData2(thread, JSTaggedValue(2)); // test metaData : 2
90     hash = TransitionsDictionary::Hash(symbolValue.GetTaggedValue(), metaData2.GetTaggedValue());
91     EXPECT_EQ(hash, 117); // 117 : 115 + 2
92 }
93 
HWTEST_F_L0(TransitionsDictionaryTest,GetKeyIndex)94 HWTEST_F_L0(TransitionsDictionaryTest, GetKeyIndex)
95 {
96     int entry = 10;
97     EXPECT_EQ(TransitionsDictionary::GetKeyIndex(entry), 33); // 33 : 3 + 10 * 3 + 0
98 }
99 
HWTEST_F_L0(TransitionsDictionaryTest,GetValueIndex)100 HWTEST_F_L0(TransitionsDictionaryTest, GetValueIndex)
101 {
102     int entry = 10;
103     EXPECT_EQ(TransitionsDictionary::GetValueIndex(entry), 34); // 34 : 3 + 10 * 3 + 1
104 }
105 
HWTEST_F_L0(TransitionsDictionaryTest,GetEntryIndex)106 HWTEST_F_L0(TransitionsDictionaryTest, GetEntryIndex)
107 {
108     int entry = 10;
109     EXPECT_EQ(TransitionsDictionary::GetEntryIndex(entry), 33); // 33 : 3 + 10 * 3
110 }
111 
HWTEST_F_L0(TransitionsDictionaryTest,Create)112 HWTEST_F_L0(TransitionsDictionaryTest, Create)
113 {
114     int numberOfElements = 8;
115     JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements);
116     EXPECT_EQ(transDic->GetLength(), 27U); // 27 : 3 + 8 * 3
117     EXPECT_EQ(transDic->EntriesCount(), 0);
118     EXPECT_EQ(transDic->HoleEntriesCount(), 0);
119 }
120 
HWTEST_F_L0(TransitionsDictionaryTest,Shrink)121 HWTEST_F_L0(TransitionsDictionaryTest, Shrink)
122 {
123     auto vm = thread->GetEcmaVM();
124     auto factory = vm->GetFactory();
125     int numberOfElements = 64;
126     JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements);
127     EXPECT_EQ(transDic->GetLength(), 195U); // 195 : 3 + 64 * 3
128     EXPECT_EQ(transDic->EntriesCount(), 0);
129 
130     JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined());
131     int eleNum = 7;
132     for (int index = 0; index < eleNum; index++) {
133         std::string keyStr = "key" + std::to_string(index);
134         std::string valueStr = "value" + std::to_string(index);
135         JSHandle<JSTaggedValue> key(factory->NewFromStdString(keyStr));
136         JSHandle<JSTaggedValue> value(factory->NewFromStdString(valueStr));
137         TransitionsDictionary::PutIfAbsent(thread, transDic, key, value, metaData);
138     }
139     JSHandle<TransitionsDictionary> transDicAfterShink = TransitionsDictionary::Shrink(thread, transDic);
140     EXPECT_EQ(transDicAfterShink->GetLength(), 51U); // (1 << (32 - Clz((7 + (7 >> 1)) - 1))) * 3 + 3
141     EXPECT_EQ(transDic->EntriesCount(), eleNum);
142 }
143 
HWTEST_F_L0(TransitionsDictionaryTest,Get_Set_Attributes)144 HWTEST_F_L0(TransitionsDictionaryTest, Get_Set_Attributes)
145 {
146     int numberOfElements = 8;
147     JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements);
148     uint32_t length = transDic->GetLength();
149     EXPECT_EQ(length, 27U); // 27 : 3 + 8 * 3
150 
151     for (int index = 0; index < numberOfElements; index++) {
152         transDic->SetAttributes(thread, index, JSTaggedValue(index));
153         JSTaggedValue value = transDic->GetAttributes(index);
154         EXPECT_EQ(value, JSTaggedValue(index));
155     }
156 }
157 
HWTEST_F_L0(TransitionsDictionaryTest,SetEntry)158 HWTEST_F_L0(TransitionsDictionaryTest, SetEntry)
159 {
160     auto vm = thread->GetEcmaVM();
161     auto factory = vm->GetFactory();
162     int numberOfElements = 8;
163     JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements);
164     JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined());
165     for (int index = 0; index < numberOfElements; index++) {
166         std::string keyStr = "key" + std::to_string(index);
167         std::string valueStr = "value" + std::to_string(index);
168         JSHandle<JSTaggedValue> key(factory->NewFromStdString(keyStr));
169         JSHandle<JSTaggedValue> value(factory->NewFromStdString(valueStr));
170         transDic->SetEntry(thread, index, key.GetTaggedValue(), value.GetTaggedValue(), metaData.GetTaggedValue());
171         EXPECT_EQ(transDic->GetKey(index), key.GetTaggedValue());
172     }
173 }
174 
HWTEST_F_L0(TransitionsDictionaryTest,FindEntry)175 HWTEST_F_L0(TransitionsDictionaryTest, FindEntry)
176 {
177     auto vm = thread->GetEcmaVM();
178     auto factory = vm->GetFactory();
179     int numberOfElements = 8;
180     JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements);
181     JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined());
182     for (int index = 0; index < numberOfElements; index++) {
183         std::string keyStr = "key" + std::to_string(index);
184         std::string valueStr = "value" + std::to_string(index);
185         JSHandle<JSTaggedValue> key(factory->NewFromStdString(keyStr));
186         JSHandle<JSTaggedValue> value(factory->NewFromStdString(valueStr));
187         transDic = TransitionsDictionary::PutIfAbsent(thread, transDic, key, value, metaData);
188         int foundEntry = transDic->FindEntry(key.GetTaggedValue(), metaData.GetTaggedValue());
189         EXPECT_EQ(index + 3, foundEntry); // 3 : table header size
190     }
191 }
192 
HWTEST_F_L0(TransitionsDictionaryTest,RemoveElement)193 HWTEST_F_L0(TransitionsDictionaryTest, RemoveElement)
194 {
195     auto vm = thread->GetEcmaVM();
196     auto factory = vm->GetFactory();
197     int numberOfElements = 8;
198     JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements);
199     JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined());
200     for (int index = 0; index < numberOfElements; index++) {
201         std::string keyStr = "key" + std::to_string(index);
202         std::string valueStr = "value" + std::to_string(index);
203         JSHandle<JSTaggedValue> key(factory->NewFromStdString(keyStr));
204         JSHandle<JSTaggedValue> value(factory->NewFromStdString(valueStr));
205         transDic = TransitionsDictionary::PutIfAbsent(thread, transDic, key, value, metaData);
206     }
207     JSHandle<JSTaggedValue> key7(factory->NewFromStdString("key7")); // test remove element by "key7"
208     int foundEntry = transDic->FindEntry(key7.GetTaggedValue(), metaData.GetTaggedValue());
209     EXPECT_EQ(foundEntry, 7 + 3);
210     EXPECT_EQ(transDic->EntriesCount(), 8);
211 
212     transDic->RemoveElement(thread, foundEntry);
213     foundEntry = transDic->FindEntry(key7.GetTaggedValue(), metaData.GetTaggedValue());
214     EXPECT_EQ(foundEntry, -1); // -1 : not found entry
215     EXPECT_EQ(transDic->EntriesCount(), 7);
216 }
217 
HWTEST_F_L0(TransitionsDictionaryTest,PutIfAbsent)218 HWTEST_F_L0(TransitionsDictionaryTest, PutIfAbsent)
219 {
220     auto vm = thread->GetEcmaVM();
221     auto factory = vm->GetFactory();
222     int numberOfElements = 8;
223     JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements);
224     JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined());
225     vm->SetEnableForceGC(false);
226     for (int index = 0; index < numberOfElements; index++) {
227         std::string keyStr = "key" + std::to_string(index);
228         std::string valueStr = "value" + std::to_string(index);
229         JSHandle<JSTaggedValue> key(factory->NewFromStdString(keyStr));
230         JSHandle<JSTaggedValue> value(factory->NewFromStdString(valueStr));
231         transDic = TransitionsDictionary::PutIfAbsent(thread, transDic, key, value, metaData);
232         int foundEntry = transDic->FindEntry(key.GetTaggedValue(), metaData.GetTaggedValue());
233         EXPECT_EQ(foundEntry, index + 3);
234 
235         JSHandle<JSTaggedValue> foundValue(thread, transDic->GetValue(foundEntry));
236         JSHandle<JSTaggedValue> weakValue(thread, value->CreateAndGetWeakRef());
237         EXPECT_EQ(foundValue.GetTaggedValue(), weakValue.GetTaggedValue());
238     }
239     vm->SetEnableForceGC(true);
240 }
241 
HWTEST_F_L0(TransitionsDictionaryTest,Remove)242 HWTEST_F_L0(TransitionsDictionaryTest, Remove)
243 {
244     auto vm = thread->GetEcmaVM();
245     auto factory = vm->GetFactory();
246     int numberOfElements = 64;
247     int eleNum = 7;
248     JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements);
249     JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined());
250     for (int index = 0; index < eleNum; index++) {
251         std::string keyStr = "key" + std::to_string(index);
252         std::string valueStr = "value" + std::to_string(index);
253         JSHandle<JSTaggedValue> key(factory->NewFromStdString(keyStr));
254         JSHandle<JSTaggedValue> value(factory->NewFromStdString(valueStr));
255         transDic = TransitionsDictionary::PutIfAbsent(thread, transDic, key, value, metaData);
256     }
257     JSHandle<JSTaggedValue> key6(factory->NewFromStdString("key6")); // test remove element by "key6"
258     EXPECT_EQ(transDic->EntriesCount(), 7);
259     EXPECT_EQ(transDic->GetLength(), 195U); // 195 : 3 + 64 * 3
260 
261     transDic = TransitionsDictionary::Remove(thread, transDic, key6, metaData.GetTaggedValue());
262     EXPECT_EQ(transDic->EntriesCount(), 6); // 6 : 7 - 1
263     EXPECT_EQ(transDic->GetLength(), 51U);  // (1 << (32 - Clz((6 + (6 >> 1)) - 1))) * 3 + 3
264 }
265 
HWTEST_F_L0(TransitionsDictionaryTest,Rehash)266 HWTEST_F_L0(TransitionsDictionaryTest, Rehash)
267 {
268     auto vm = thread->GetEcmaVM();
269     auto factory = vm->GetFactory();
270     int numberOfElements = 64;
271     int eleNum = 7;
272     JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements);
273     JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined());
274     for (int index = 0; index < eleNum; index++) {
275         std::string keyStr = "key" + std::to_string(index);
276         std::string valueStr = "value" + std::to_string(index);
277         JSHandle<JSTaggedValue> key(factory->NewFromStdString(keyStr));
278         JSHandle<JSTaggedValue> value(factory->NewFromStdString(valueStr));
279         transDic = TransitionsDictionary::PutIfAbsent(thread, transDic, key, value, metaData);
280     }
281     EXPECT_EQ(transDic->HoleEntriesCount(), 0);
282 
283     int lastEntry = 7 + 3;
284     transDic->RemoveElement(thread, lastEntry); // remove one element
285     EXPECT_EQ(transDic->HoleEntriesCount(), 1);
286 
287     transDic->Rehash(thread, *transDic);
288     EXPECT_EQ(transDic->HoleEntriesCount(), 0);
289 }
290 }  // namespace panda::test