• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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/tests/test_helper.h"
17 
18 #include "ecmascript/ecma_vm.h"
19 #include "ecmascript/global_env.h"
20 #include "ecmascript/js_handle.h"
21 #include "ecmascript/js_hclass.h"
22 #include "ecmascript/js_thread.h"
23 #include "ecmascript/jspandafile/program_object.h"
24 #include "ecmascript/object_factory.h"
25 #include "ecmascript/snapshot/mem/snapshot.h"
26 #include "ecmascript/snapshot/mem/snapshot_processor.h"
27 #include "ecmascript/snapshot/tests/snapshot_mock.h"
28 #include "ecmascript/ts_types/ts_manager.h"
29 
30 using namespace panda::ecmascript;
31 
32 namespace panda::test {
33 class SnapshotTest : public testing::Test {
34 public:
SetUpTestCase()35     static void SetUpTestCase()
36     {
37         GTEST_LOG_(INFO) << "SetUpTestCase";
38     }
39 
TearDownTestCase()40     static void TearDownTestCase()
41     {
42         GTEST_LOG_(INFO) << "TearDownCase";
43     }
44 
SetUp()45     void SetUp() override
46     {
47         JSRuntimeOptions options;
48         ecmaVm = JSNApi::CreateEcmaVM(options);
49         ASSERT_TRUE(ecmaVm != nullptr) << "Cannot create EcmaVM";
50         thread = ecmaVm->GetJSThread();
51         scope = new EcmaHandleScope(thread);
52     }
53 
TearDown()54     void TearDown() override
55     {
56         delete scope;
57         scope = nullptr;
58         ecmaVm->SetEnableForceGC(false);
59         thread->ClearException();
60         JSNApi::DestroyJSVM(ecmaVm);
61     }
62 
CompatibilityHelper(base::FileHeaderBase::VersionType serializeVersion,base::FileHeaderBase::VersionType deserializeVersion,bool expected)63     void CompatibilityHelper(base::FileHeaderBase::VersionType serializeVersion,
64                              base::FileHeaderBase::VersionType deserializeVersion, bool expected)
65     {
66         static constexpr uint32_t ARRAY_SIZE = 300;
67         static constexpr uint32_t KILO_BITS = 1024;
68         auto factory = ecmaVm->GetFactory();
69         auto env = ecmaVm->GetGlobalEnv();
70 
71         JSHandle<TaggedArray> array1 = factory->NewTaggedArray(ARRAY_SIZE * KILO_BITS / sizeof(uint8_t));
72 
73         JSHandle<JSFunction> funcFunc(env->GetFunctionFunction());
74         array1->Set(thread, 0, funcFunc.GetTaggedValue());
75 
76         CString fileName = "snapshot";
77         SnapshotMock snapshotSerialize(ecmaVm);
78         snapshotSerialize.SetLastVersion(serializeVersion);
79         // serialize in earlier version tag
80         snapshotSerialize.Serialize(*array1, nullptr, fileName);
81 
82         JSRuntimeOptions options;
83         EcmaVM *ecmaVm2 = JSNApi::CreateEcmaVM(options);
84         // deserialize with last version tag
85         SnapshotMock snapshotDeserialize(ecmaVm2);
86         snapshotDeserialize.SetLastVersion(deserializeVersion);
87         EXPECT_EQ(snapshotDeserialize.Deserialize(SnapshotType::VM_ROOT, fileName), expected);
88 
89         ASSERT_EQ(const_cast<Heap *>(ecmaVm2->GetHeap())->GetHugeObjectSpace()->GetFirstRegion() != nullptr, expected);
90         JSNApi::DestroyJSVM(ecmaVm2);
91         std::remove(fileName.c_str());
92     }
93 
94     EcmaVM *ecmaVm {nullptr};
95     ecmascript::EcmaHandleScope *scope {nullptr};
96     JSThread *thread {nullptr};
97 };
98 
HWTEST_F_L0(SnapshotTest,SerializeConstPool)99 HWTEST_F_L0(SnapshotTest, SerializeConstPool)
100 {
101     auto factory = ecmaVm->GetFactory();
102     auto env = ecmaVm->GetGlobalEnv();
103 
104     JSHandle<ConstantPool> constpool = factory->NewConstantPool(10);
105     JSHandle<JSFunction> funcFunc(env->GetFunctionFunction());
106     JSHandle<JSFunction> dateFunc(env->GetDateFunction());
107     JSHandle<JSFunction> numberFunc(env->GetNumberFunction());
108     JSHandle<EcmaString> str1 = factory->NewFromASCII("str11");
109     JSHandle<EcmaString> str2 = factory->NewFromASCII("str22");
110     JSHandle<EcmaString> str3 = factory->NewFromASCII("str333333333333");
111     JSHandle<EcmaString> str4 = factory->ConcatFromString(str1, str3);
112     JSHandle<EcmaString> str5 = factory->NewFromASCII("str44");
113     constpool->SetObjectToCache(thread, 0, funcFunc.GetTaggedValue());
114     constpool->SetObjectToCache(thread, 1, dateFunc.GetTaggedValue());
115     constpool->SetObjectToCache(thread, 2, str1.GetTaggedValue());
116     constpool->SetObjectToCache(thread, 3, numberFunc.GetTaggedValue());
117     constpool->SetObjectToCache(thread, 4, str2.GetTaggedValue());
118     constpool->SetObjectToCache(thread, 5, str1.GetTaggedValue());
119     constpool->SetObjectToCache(thread, 6, str3.GetTaggedValue());
120     constpool->SetObjectToCache(thread, 7, str4.GetTaggedValue());
121     constpool->SetObjectToCache(thread, 8, str4.GetTaggedValue());
122     constpool->SetObjectToCache(thread, 9, str5.GetTaggedValue());
123 
124     CString fileName = "snapshot";
125     Snapshot snapshotSerialize(ecmaVm);
126     // serialize
127     snapshotSerialize.Serialize(*constpool, nullptr, fileName);
128     // deserialize
129     Snapshot snapshotDeserialize(ecmaVm);
130     snapshotDeserialize.Deserialize(SnapshotType::VM_ROOT, fileName);
131 
132     auto beginRegion = const_cast<Heap *>(ecmaVm->GetHeap())->GetOldSpace()->GetCurrentRegion();
133     auto constpool1 = reinterpret_cast<ConstantPool *>(beginRegion->GetBegin());
134     EXPECT_EQ(constpool->GetClass()->SizeFromJSHClass(*constpool),
135               constpool1->GetClass()->SizeFromJSHClass(constpool1));
136     EXPECT_TRUE(constpool1->GetObjectFromCache(0).IsJSFunction());
137     EXPECT_TRUE(constpool1->GetObjectFromCache(1).IsJSFunction());
138     EXPECT_TRUE(constpool1->GetObjectFromCache(3).IsJSFunction());
139     EcmaString *str11 = reinterpret_cast<EcmaString *>(constpool1->Get(2).GetTaggedObject());
140     EcmaString *str22 = reinterpret_cast<EcmaString *>(constpool1->Get(4).GetTaggedObject());
141     EcmaString *str33 = reinterpret_cast<EcmaString *>(constpool1->Get(5).GetTaggedObject());
142     EcmaString *str44 = reinterpret_cast<EcmaString *>(constpool1->Get(6).GetTaggedObject());
143     EcmaString *str55 = reinterpret_cast<EcmaString *>(constpool1->Get(7).GetTaggedObject());
144     EcmaString *str66 = reinterpret_cast<EcmaString *>(constpool1->Get(8).GetTaggedObject());
145     EcmaString *str77 = reinterpret_cast<EcmaString *>(constpool1->Get(9).GetTaggedObject());
146     EXPECT_EQ(std::strcmp(EcmaStringAccessor(str11).ToCString().c_str(), "str11"), 0);
147     EXPECT_EQ(std::strcmp(EcmaStringAccessor(str22).ToCString().c_str(), "str22"), 0);
148     EXPECT_EQ(std::strcmp(EcmaStringAccessor(str33).ToCString().c_str(), "str11"), 0);
149     EXPECT_EQ(std::strcmp(EcmaStringAccessor(str44).ToCString().c_str(), "str333333333333"), 0);
150     EXPECT_EQ(std::strcmp(EcmaStringAccessor(str55).ToCString().c_str(), "str11str333333333333"), 0);
151     EXPECT_EQ(std::strcmp(EcmaStringAccessor(str66).ToCString().c_str(), "str11str333333333333"), 0);
152     EXPECT_EQ(std::strcmp(EcmaStringAccessor(str77).ToCString().c_str(), "str44"), 0);
153     std::remove(fileName.c_str());
154 }
155 
HWTEST_F_L0(SnapshotTest,SerializeDifferentSpace)156 HWTEST_F_L0(SnapshotTest, SerializeDifferentSpace)
157 {
158     auto factory = ecmaVm->GetFactory();
159     JSHandle<ConstantPool> constpool = factory->NewConstantPool(400);
160     for (int i = 0; i < 100; i++) {
161         JSHandle<TaggedArray> array = factory->NewTaggedArray(10, JSTaggedValue::Hole(), MemSpaceType::SEMI_SPACE);
162         constpool->SetObjectToCache(thread, i, array.GetTaggedValue());
163     }
164     for (int i = 0; i < 100; i++) {
165         JSHandle<TaggedArray> array = factory->NewTaggedArray(10, JSTaggedValue::Hole(), MemSpaceType::OLD_SPACE);
166         constpool->SetObjectToCache(thread, i + 100, array.GetTaggedValue());
167     }
168     for (int i = 0; i < 100; i++) {
169         JSHandle<ConstantPool> constpool1 = factory->NewConstantPool(10);
170         constpool->SetObjectToCache(thread, i + 300, constpool1.GetTaggedValue());
171     }
172 
173     CString fileName = "snapshot";
174     Snapshot snapshotSerialize(ecmaVm);
175     // serialize
176     snapshotSerialize.Serialize(*constpool, nullptr, fileName);
177     // deserialize
178     Snapshot snapshotDeserialize(ecmaVm);
179     snapshotDeserialize.Deserialize(SnapshotType::VM_ROOT, fileName);
180 
181     auto beginRegion = const_cast<Heap *>(ecmaVm->GetHeap())->GetOldSpace()->GetCurrentRegion();
182     auto constpool1 = reinterpret_cast<ConstantPool *>(beginRegion->GetBegin());
183     EXPECT_EQ(constpool->GetClass()->SizeFromJSHClass(*constpool),
184               constpool1->GetClass()->SizeFromJSHClass(constpool1));
185     EXPECT_TRUE(constpool1->GetObjectFromCache(0).IsTaggedArray());
186     EXPECT_TRUE(constpool1->GetObjectFromCache(100).IsTaggedArray());
187     EXPECT_TRUE(constpool1->GetObjectFromCache(300).IsTaggedArray());
188 
189     auto obj1 = constpool1->GetObjectFromCache(0).GetTaggedObject();
190     EXPECT_TRUE(Region::ObjectAddressToRange(obj1)->InOldSpace());
191     auto obj2 = constpool1->GetObjectFromCache(100).GetTaggedObject();
192     EXPECT_TRUE(Region::ObjectAddressToRange(obj2)->InOldSpace());
193     std::remove(fileName.c_str());
194 }
195 
HWTEST_F_L0(SnapshotTest,SerializeMultiFile)196 HWTEST_F_L0(SnapshotTest, SerializeMultiFile)
197 {
198     auto factory = ecmaVm->GetFactory();
199     JSHandle<ConstantPool> constpool1 = factory->NewConstantPool(400);
200     JSHandle<ConstantPool> constpool2 = factory->NewConstantPool(400);
201     for (int i = 0; i < 100; i++) {
202         JSHandle<TaggedArray> array = factory->NewTaggedArray(10, JSTaggedValue::Hole(), MemSpaceType::SEMI_SPACE);
203         constpool1->SetObjectToCache(thread, i, array.GetTaggedValue());
204         constpool2->SetObjectToCache(thread, i, array.GetTaggedValue());
205     }
206     for (int i = 0; i < 100; i++) {
207         JSHandle<TaggedArray> array = factory->NewTaggedArray(10, JSTaggedValue::Hole(), MemSpaceType::OLD_SPACE);
208         constpool1->SetObjectToCache(thread, i + 100, array.GetTaggedValue());
209         constpool2->SetObjectToCache(thread, i + 100, array.GetTaggedValue());
210     }
211     for (int i = 0; i < 100; i++) {
212         JSHandle<ConstantPool> constpool3 = factory->NewConstantPool(10);
213         constpool1->SetObjectToCache(thread, i + 300, constpool3.GetTaggedValue());
214         constpool2->SetObjectToCache(thread, i + 300, constpool3.GetTaggedValue());
215     }
216 
217     CString fileName1 = "snapshot1";
218     CString fileName2 = "snapshot2";
219     Snapshot snapshotSerialize(ecmaVm);
220     // serialize
221     snapshotSerialize.Serialize(*constpool1, nullptr, fileName1);
222     snapshotSerialize.Serialize(*constpool2, nullptr, fileName2);
223     // deserialize
224     Snapshot snapshotDeserialize(ecmaVm);
225     snapshotDeserialize.Deserialize(SnapshotType::VM_ROOT, fileName1);
226     snapshotDeserialize.Deserialize(SnapshotType::VM_ROOT, fileName2);
227 
228     auto beginRegion = const_cast<Heap *>(ecmaVm->GetHeap())->GetOldSpace()->GetCurrentRegion();
229     auto constpool = reinterpret_cast<ConstantPool *>(beginRegion->GetBegin());
230     EXPECT_TRUE(constpool->GetObjectFromCache(0).IsTaggedArray());
231     EXPECT_TRUE(constpool->GetObjectFromCache(100).IsTaggedArray());
232     auto obj1 = constpool->GetObjectFromCache(0).GetTaggedObject();
233     EXPECT_TRUE(Region::ObjectAddressToRange(obj1)->InOldSpace());
234     auto obj2 = constpool->GetObjectFromCache(100).GetTaggedObject();
235     EXPECT_TRUE(Region::ObjectAddressToRange(obj2)->InOldSpace());
236     std::remove(fileName1.c_str());
237     std::remove(fileName2.c_str());
238 }
239 
HWTEST_F_L0(SnapshotTest,SerializeBuiltins)240 HWTEST_F_L0(SnapshotTest, SerializeBuiltins)
241 {
242     // remove builtins.snapshot file first if exist
243     CString fileName = "builtins.snapshot";
244     std::remove(fileName.c_str());
245     // generate builtins.snapshot file
246     JSRuntimeOptions options1;
247     options1.SetArkProperties(ArkProperties::ENABLE_SNAPSHOT_SERIALIZE);
248     EcmaVM *ecmaVm1 = JSNApi::CreateEcmaVM(options1);
249     JSNApi::DestroyJSVM(ecmaVm1);
250 
251     // create EcmaVM use builtins deserialzie
252     JSRuntimeOptions options2;
253     options2.SetArkProperties(ArkProperties::ENABLE_SNAPSHOT_DESERIALIZE);
254     EcmaVM *ecmaVm2 = JSNApi::CreateEcmaVM(options2);
255     EXPECT_TRUE(ecmaVm2->GetGlobalEnv()->GetClass()->GetObjectType() == JSType::GLOBAL_ENV);
256     auto globalConst = const_cast<GlobalEnvConstants *>(ecmaVm2->GetJSThread()->GlobalConstants());
257     size_t hclassEndIndex = static_cast<size_t>(ConstantIndex::UNDEFINED_INDEX);
258     size_t hclassIndex = 0;
259     globalConst->VisitRangeSlot([&hclassIndex, &hclassEndIndex]([[maybe_unused]] Root type,
260                                                                 ObjectSlot start, ObjectSlot end) {
261         while (start < end) {
262             JSTaggedValue object(start.GetTaggedType());
263             start++;
264             if (hclassIndex < hclassEndIndex) {
265                 EXPECT_TRUE(object.IsJSHClass());
266             }
267             hclassIndex++;
268         }
269     });
270     JSNApi::DestroyJSVM(ecmaVm2);
271 
272     std::remove(fileName.c_str());
273 }
274 
HWTEST_F_L0(SnapshotTest,SerializeHugeObject)275 HWTEST_F_L0(SnapshotTest, SerializeHugeObject)
276 {
277     auto factory = ecmaVm->GetFactory();
278     auto env = ecmaVm->GetGlobalEnv();
279 
280     JSHandle<TaggedArray> array1 = factory->NewTaggedArray(300 * 1024 / 8);
281     JSHandle<TaggedArray> array2 = factory->NewTaggedArray(300 * 1024 / 8);
282     JSHandle<TaggedArray> array3 = factory->NewTaggedArray(100);
283 
284     JSHandle<JSFunction> funcFunc(env->GetFunctionFunction());
285     JSHandle<JSFunction> dateFunc(env->GetDateFunction());
286     JSHandle<JSFunction> numberFunc(env->GetNumberFunction());
287     array1->Set(thread, 0, array2.GetTaggedValue());
288     array1->Set(thread, 1, funcFunc.GetTaggedValue());
289     array1->Set(thread, 2, dateFunc.GetTaggedValue());
290     array1->Set(thread, 3, numberFunc.GetTaggedValue());
291     array2->Set(thread, 0, array3.GetTaggedValue());
292     array2->Set(thread, 1, funcFunc.GetTaggedValue());
293     array2->Set(thread, 2, dateFunc.GetTaggedValue());
294     array2->Set(thread, 3, numberFunc.GetTaggedValue());
295 
296     CString fileName = "snapshot";
297     Snapshot snapshotSerialize(ecmaVm);
298     // serialize
299     snapshotSerialize.Serialize(*array1, nullptr, fileName);
300     // deserialize
301     Snapshot snapshotDeserialize(ecmaVm);
302     snapshotDeserialize.Deserialize(SnapshotType::VM_ROOT, fileName);
303 
304     auto lastRegion = const_cast<Heap *>(ecmaVm->GetHeap())->GetHugeObjectSpace()->GetCurrentRegion();
305     auto array4 = reinterpret_cast<TaggedArray *>(lastRegion->GetBegin());
306     EXPECT_TRUE(array4->Get(0).IsTaggedArray());
307     EXPECT_TRUE(array4->Get(1).IsJSFunction());
308     EXPECT_TRUE(array4->Get(2).IsJSFunction());
309     EXPECT_TRUE(array4->Get(3).IsJSFunction());
310     std::remove(fileName.c_str());
311 }
312 
HWTEST_F_L0(SnapshotTest,BackwardCompatibility)313 HWTEST_F_L0(SnapshotTest, BackwardCompatibility)
314 {
315     base::FileHeaderBase::VersionType oldVersion = {0, 0, 0, 1};
316     base::FileHeaderBase::VersionType newVersion = {4, 0, 0, 1};
317     CompatibilityHelper(oldVersion, newVersion, false);
318 }
319 
HWTEST_F_L0(SnapshotTest,ForwardCompatibility)320 HWTEST_F_L0(SnapshotTest, ForwardCompatibility)
321 {
322     base::FileHeaderBase::VersionType oldVersion = {0, 0, 0, 1};
323     base::FileHeaderBase::VersionType newVersion = {4, 0, 0, 1};
324     CompatibilityHelper(newVersion, oldVersion, false);
325 }
326 
HWTEST_F_L0(SnapshotTest,StrictCompatibility)327 HWTEST_F_L0(SnapshotTest, StrictCompatibility)
328 {
329     base::FileHeaderBase::VersionType newVersion = {4, 0, 0, 1};
330     CompatibilityHelper(newVersion, newVersion, true);
331 }
332 
HWTEST_F_L0(SnapshotTest,VersionTest)333 HWTEST_F_L0(SnapshotTest, VersionTest)
334 {
335     base::FileHeaderBase::VersionType version = {4, 3, 2, 1};
336     uint32_t versionNumber = 0x04030201U;
337     EXPECT_EQ(version, base::FileHeaderBase::ToVersion(versionNumber));
338     EXPECT_EQ(versionNumber, base::FileHeaderBase::ToVersionNumber(version));
339 }
340 
341 }  // namespace panda::test
342