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