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/tagged_array.h"
17 #include "ecmascript/global_env.h"
18 #include "ecmascript/tests/test_helper.h"
19
20 using namespace panda::ecmascript;
21
22 namespace panda::test {
23 class TaggedArrayTest : public testing::Test {
24 public:
SetUpTestCase()25 static void SetUpTestCase()
26 {
27 GTEST_LOG_(INFO) << "SetUpTestCase";
28 }
29
TearDownTestCase()30 static void TearDownTestCase()
31 {
32 GTEST_LOG_(INFO) << "TearDownCase";
33 }
34
SetUp()35 void SetUp() override
36 {
37 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
38 }
39
TearDown()40 void TearDown() override
41 {
42 TestHelper::DestroyEcmaVMWithScope(instance, scope);
43 }
44
45 EcmaVM *instance {nullptr};
46 EcmaHandleScope *scope {nullptr};
47 JSThread *thread {nullptr};
48 };
49
JSArrayTestCreate(JSThread * thread)50 static JSObject *JSArrayTestCreate(JSThread *thread)
51 {
52 [[maybe_unused]] ecmascript::EcmaHandleScope scope(thread);
53 EcmaVM *ecmaVM = thread->GetEcmaVM();
54 auto globalEnv = ecmaVM->GetGlobalEnv();
55 JSHandle<JSTaggedValue> jsFunc = globalEnv->GetArrayFunction();
56 JSHandle<JSObject> newArray =
57 ecmaVM->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>(jsFunc), jsFunc);
58 return *newArray;
59 }
60
HWTEST_F_L0(TaggedArrayTest,Create)61 HWTEST_F_L0(TaggedArrayTest, Create)
62 {
63 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
64 uint32_t arrayLength = 2;
65 JSHandle<TaggedArray> taggedArray = factory->NewTaggedArray(arrayLength);
66 EXPECT_TRUE(*taggedArray != nullptr);
67 // every element of the taggedarray is JSTaggedValue::Hole()
68 for (uint32_t i = 0; i < arrayLength; i++) {
69 EXPECT_TRUE(taggedArray->Get(i).IsHole());
70 }
71 }
72
HWTEST_F_L0(TaggedArrayTest,SetAndGetIdx)73 HWTEST_F_L0(TaggedArrayTest, SetAndGetIdx)
74 {
75 EcmaVM *ecmaVM = thread->GetEcmaVM();
76 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
77 uint32_t arrayLength = 2;
78 JSHandle<TaggedArray> taggedArray = factory->NewTaggedArray(arrayLength);
79
80 JSHandle<JSObject> newObj1(thread, JSArrayTestCreate(thread));
81 JSObject *newObj2 = JSArrayTestCreate(thread);
82 JSTaggedValue objValue(newObj2);
83 taggedArray->Set(thread, 0, newObj1);
84 taggedArray->Set(thread, 1, objValue);
85
86 EXPECT_EQ(taggedArray->GetIdx(newObj1.GetTaggedValue()), 0U);
87 EXPECT_EQ(taggedArray->GetIdx(objValue), 1U);
88 // trigger gc
89 ecmaVM->CollectGarbage(TriggerGCType::OLD_GC);
90 EXPECT_EQ(taggedArray->GetIdx(newObj1.GetTaggedValue()), 0U);
91 EXPECT_EQ(taggedArray->GetIdx(objValue), TaggedArray::MAX_ARRAY_INDEX);
92 }
93
HWTEST_F_L0(TaggedArrayTest,Append)94 HWTEST_F_L0(TaggedArrayTest, Append)
95 {
96 EcmaVM *ecmaVM = thread->GetEcmaVM();
97 ecmaVM->SetEnableForceGC(false); // turn off GC
98 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
99 uint32_t arrayLength = 2;
100 JSHandle<TaggedArray> taggedArray1 = factory->NewTaggedArray(arrayLength);
101 JSHandle<TaggedArray> taggedArray2 = factory->NewTaggedArray(arrayLength);
102 // create value of the taggedarray
103 JSHandle<JSObject> newObj1(thread, JSArrayTestCreate(thread));
104 JSObject *newObj2 = JSArrayTestCreate(thread);
105 JSTaggedValue objValue(newObj2);
106 // set value to the taggedarray
107 taggedArray1->Set(thread, 0, newObj1);
108 taggedArray1->Set(thread, 1, JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined()));
109 taggedArray2->Set(thread, 0, objValue);
110 taggedArray2->Set(thread, 1, JSTaggedValue::Undefined());
111 // append two taggedarray
112 JSHandle<TaggedArray> appendArray = TaggedArray::Append(thread, taggedArray1, taggedArray2);
113 EXPECT_EQ(appendArray->GetLength(), arrayLength * 2);
114 EXPECT_EQ(appendArray->Get(0), newObj1.GetTaggedValue());
115 EXPECT_EQ(appendArray->Get(2), objValue); // 2: the second index
116 EXPECT_EQ(appendArray->Get(1), appendArray->Get(3)); // 3: the third index
117 ecmaVM->SetEnableForceGC(true); // turn on GC
118 }
119
HWTEST_F_L0(TaggedArrayTest,AppendSkipHole)120 HWTEST_F_L0(TaggedArrayTest, AppendSkipHole)
121 {
122 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
123 uint32_t arrayLength = 2;
124 uint32_t twoArrayLength = arrayLength * 2 + 1;
125 JSHandle<TaggedArray> taggedArray1 = factory->NewTaggedArray(arrayLength + 1);
126 JSHandle<TaggedArray> taggedArray2 = factory->NewTaggedArray(arrayLength);
127 // create value of the taggedarray
128 JSHandle<JSObject> newObj1(thread, JSArrayTestCreate(thread));
129 // set value to the taggedarray
130 taggedArray1->Set(thread, 0, newObj1);
131 taggedArray1->Set(thread, 1, newObj1.GetTaggedValue());
132 taggedArray1->Set(thread, 2, JSHandle<JSTaggedValue>(thread, JSTaggedValue::Undefined()));
133 taggedArray2->Set(thread, 1, newObj1.GetTaggedValue());
134 // append two taggedarray
135 JSHandle<TaggedArray> appendArray = TaggedArray::AppendSkipHole(thread, taggedArray1, taggedArray2, twoArrayLength);
136 EXPECT_EQ(appendArray->GetLength(), twoArrayLength);
137 EXPECT_EQ(appendArray->Get(0), appendArray->Get(1));
138 EXPECT_TRUE(appendArray->Get(2).IsUndefined()); // 2: the second index
139 EXPECT_TRUE(appendArray->Get(3).IsHole()); // 3: the third index
140 EXPECT_TRUE(appendArray->Get(4).IsHole()); // 4: the fourth index
141 }
142
HWTEST_F_L0(TaggedArrayTest,HasDuplicateEntry)143 HWTEST_F_L0(TaggedArrayTest, HasDuplicateEntry)
144 {
145 EcmaVM *ecmaVM = thread->GetEcmaVM();
146 ObjectFactory *factory = ecmaVM->GetFactory();
147 uint32_t arrayLength = 10;
148 JSHandle<TaggedArray> taggedArray = factory->NewTaggedArray(arrayLength);
149 JSHandle<JSTaggedValue> value1(thread, JSTaggedValue(1)); // 1: means value
150 JSHandle<JSTaggedValue> value3(thread, JSTaggedValue(3)); // 3: means value
151
152 JSHandle<JSObject> newObj1(thread, JSArrayTestCreate(thread));
153 JSObject *newObj2 = JSArrayTestCreate(thread);
154 JSTaggedValue objValue(newObj2);
155 for (uint32_t i = 0; i < arrayLength; i++) {
156 JSHandle<JSTaggedValue> arrayValue(thread, JSTaggedValue(i));
157 taggedArray->Set(thread, i, arrayValue.GetTaggedValue());
158 }
159 EXPECT_FALSE(taggedArray->HasDuplicateEntry());
160 // set value that is the same as the thrid index
161 taggedArray->Set(thread, 1, value3.GetTaggedValue());
162 EXPECT_TRUE(taggedArray->HasDuplicateEntry());
163 // resert value in the second index
164 taggedArray->Set(thread, 1, value1.GetTaggedValue());
165 taggedArray->Set(thread, 5, newObj1); // 5: the fifth index
166 taggedArray->Set(thread, 6, newObj1.GetTaggedValue()); // 6: the sixth index
167 EXPECT_TRUE(taggedArray->HasDuplicateEntry());
168 }
169
HWTEST_F_L0(TaggedArrayTest,Trim)170 HWTEST_F_L0(TaggedArrayTest, Trim)
171 {
172 uint32_t oldArrayLength = 10;
173 uint32_t newArrayLength = 5;
174 auto globalEnv = thread->GetEcmaVM()->GetGlobalEnv();
175 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
176 JSHandle<JSTaggedValue> indexValue(thread, JSTaggedValue(6));
177 JSHandle<JSTaggedValue> undefinedValue(thread, JSTaggedValue::Undefined());
178
179 JSHandle<JSTaggedValue> jsFunc = globalEnv->GetObjectFunction();
180 JSHandle<JSObject> TaggedArrayObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(jsFunc), jsFunc);
181 // Create taggedarray with oldArrayLength
182 JSHandle<TaggedArray> taggedArray = factory->NewTaggedArray(oldArrayLength);
183 for (uint32_t i = 0; i < oldArrayLength; i++) {
184 JSHandle<JSTaggedValue> arrayValue(thread, JSTaggedValue(i));
185 taggedArray->Set(thread, i, arrayValue.GetTaggedValue());
186 }
187 TaggedArrayObj->SetElements(thread, taggedArray);
188 EXPECT_EQ(JSObject::GetProperty(thread, TaggedArrayObj, indexValue).GetValue(), indexValue);
189 // trim taggedarray
190 taggedArray->Trim(thread, newArrayLength);
191 for (uint32_t i = 0; i < newArrayLength; i++) {
192 JSHandle<JSTaggedValue> arrayValue(thread, JSTaggedValue(i));
193 EXPECT_EQ(taggedArray->Get(i), arrayValue.GetTaggedValue());
194 }
195 EXPECT_EQ(taggedArray->GetLength(), newArrayLength);
196 EXPECT_EQ(JSObject::GetProperty(thread, TaggedArrayObj, indexValue).GetValue(), undefinedValue);
197 }
198
HWTEST_F_L0(TaggedArrayTest,RemoveElementByIndex)199 HWTEST_F_L0(TaggedArrayTest, RemoveElementByIndex)
200 {
201 constexpr uint32_t ELEMENT_NUMS = 20;
202 constexpr uint32_t REMOVE_INDEX = 0;
203 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
204 JSHandle<TaggedArray> semiTaggedarray = factory->NewTaggedArray(ELEMENT_NUMS, JSTaggedValue::Hole(),
205 MemSpaceType::SEMI_SPACE);
206 JSHandle<TaggedArray> oldTaggedarray = factory->NewTaggedArray(ELEMENT_NUMS, JSTaggedValue::Hole(),
207 MemSpaceType::OLD_SPACE);
208 // init tagggedArray
209 for (uint32_t i = 0; i < ELEMENT_NUMS; i++) {
210 semiTaggedarray->Set(thread, i, JSTaggedValue(i));
211 oldTaggedarray->Set(thread, i, JSTaggedValue(i));
212 }
213 TaggedArray::RemoveElementByIndex(thread, semiTaggedarray, REMOVE_INDEX, ELEMENT_NUMS);
214 TaggedArray::RemoveElementByIndex(thread, oldTaggedarray, REMOVE_INDEX, ELEMENT_NUMS);
215
216 for (uint32_t i = 0; i < ELEMENT_NUMS - 1; i++) {
217 EXPECT_EQ(semiTaggedarray->Get(thread, i), JSTaggedValue(i + 1));
218 EXPECT_EQ(oldTaggedarray->Get(thread, i), JSTaggedValue(i + 1));
219 }
220 EXPECT_EQ(semiTaggedarray->Get(thread, ELEMENT_NUMS - 1), JSTaggedValue::Hole());
221 EXPECT_EQ(oldTaggedarray->Get(thread, ELEMENT_NUMS - 1), JSTaggedValue::Hole());
222 }
223
HWTEST_F_L0(TaggedArrayTest,InsertElementByIndex)224 HWTEST_F_L0(TaggedArrayTest, InsertElementByIndex)
225 {
226 constexpr uint32_t ELEMENT_NUMS = 20;
227 constexpr uint32_t INSERT_INDEX = 0;
228 JSHandle<JSTaggedValue> insertValue(thread, JSTaggedValue(ELEMENT_NUMS));
229 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
230 JSHandle<TaggedArray> semiTaggedarray = factory->NewTaggedArray(ELEMENT_NUMS, JSTaggedValue::Hole(),
231 MemSpaceType::SEMI_SPACE);
232 JSHandle<TaggedArray> oldTaggedarray = factory->NewTaggedArray(ELEMENT_NUMS, JSTaggedValue::Hole(),
233 MemSpaceType::OLD_SPACE);
234 // init tagggedArray
235 for (uint32_t i = 0; i < ELEMENT_NUMS - 1; i++) {
236 semiTaggedarray->Set(thread, i, JSTaggedValue(i));
237 oldTaggedarray->Set(thread, i, JSTaggedValue(i));
238 }
239 TaggedArray::InsertElementByIndex(thread, semiTaggedarray, insertValue, INSERT_INDEX, ELEMENT_NUMS - 1);
240 TaggedArray::InsertElementByIndex(thread, oldTaggedarray, insertValue, INSERT_INDEX, ELEMENT_NUMS - 1);
241 // check
242 EXPECT_EQ(semiTaggedarray->Get(thread, 0), insertValue.GetTaggedValue());
243 EXPECT_EQ(oldTaggedarray->Get(thread, 0), insertValue.GetTaggedValue());
244 for (uint32_t i = 1; i < ELEMENT_NUMS; i++) {
245 EXPECT_EQ(semiTaggedarray->Get(thread, i), JSTaggedValue(i - 1));
246 EXPECT_EQ(oldTaggedarray->Get(thread, i), JSTaggedValue(i - 1));
247 }
248 }
249
HWTEST_F_L0(TaggedArrayTest,CopyTaggedArrayElement)250 HWTEST_F_L0(TaggedArrayTest, CopyTaggedArrayElement)
251 {
252 constexpr uint32_t ELEMENT_NUMS = 20;
253 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
254 JSHandle<TaggedArray> srcSemiTaggedarray = factory->NewTaggedArray(ELEMENT_NUMS, JSTaggedValue::Hole(),
255 MemSpaceType::SEMI_SPACE);
256 JSHandle<TaggedArray> srcOldTaggedarray = factory->NewTaggedArray(ELEMENT_NUMS, JSTaggedValue::Hole(),
257 MemSpaceType::OLD_SPACE);
258 JSHandle<TaggedArray> dstSemiTaggedarray = factory->NewTaggedArray(ELEMENT_NUMS);
259 JSHandle<TaggedArray> dstOldTaggedarray = factory->NewTaggedArray(ELEMENT_NUMS);
260 // init tagggedArray
261 for (uint32_t i = 0; i < ELEMENT_NUMS; i++) {
262 srcSemiTaggedarray->Set(thread, i, JSTaggedValue(i));
263 srcOldTaggedarray->Set(thread, i, JSTaggedValue(i));
264 dstSemiTaggedarray->Set(thread, i, JSTaggedValue(-i));
265 dstOldTaggedarray->Set(thread, i, JSTaggedValue(-i));
266 }
267 TaggedArray::CopyTaggedArrayElement(thread, srcSemiTaggedarray, dstSemiTaggedarray, ELEMENT_NUMS);
268 TaggedArray::CopyTaggedArrayElement(thread, srcOldTaggedarray, dstOldTaggedarray, ELEMENT_NUMS);
269
270 for (uint32_t i = 0; i < ELEMENT_NUMS; i++) {
271 EXPECT_EQ(srcSemiTaggedarray->Get(thread, i), dstSemiTaggedarray->Get(thread, i));
272 EXPECT_EQ(srcOldTaggedarray->Get(thread, i), dstOldTaggedarray->Get(thread, i));
273 }
274 }
275 } // namespace panda::ecmascript