• 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/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