• 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/base/file_header.h"
17 #include "ecmascript/tests/test_helper.h"
18 
19 #include "ecmascript/ecma_vm.h"
20 #include "ecmascript/global_env.h"
21 #include "ecmascript/js_handle.h"
22 #include "ecmascript/js_hclass.h"
23 #include "ecmascript/js_thread.h"
24 #include "ecmascript/jspandafile/program_object.h"
25 #include "ecmascript/object_factory.h"
26 #include "ecmascript/snapshot/mem/snapshot.h"
27 #include "ecmascript/snapshot/mem/snapshot_processor.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 
63     EcmaVM *ecmaVm {nullptr};
64     ecmascript::EcmaHandleScope *scope {nullptr};
65     JSThread *thread {nullptr};
66 };
67 
HWTEST_F_L0(SnapshotTest,SerializeConstPool)68 HWTEST_F_L0(SnapshotTest, SerializeConstPool)
69 {
70     auto factory = ecmaVm->GetFactory();
71     auto env = ecmaVm->GetGlobalEnv();
72 
73     JSHandle<ConstantPool> constpool = factory->NewConstantPool(6);
74     JSHandle<JSFunction> funcFunc(env->GetFunctionFunction());
75     JSHandle<JSFunction> dateFunc(env->GetDateFunction());
76     JSHandle<JSFunction> numberFunc(env->GetNumberFunction());
77     JSHandle<EcmaString> str1 = factory->NewFromASCII("str11");
78     JSHandle<EcmaString> str2 = factory->NewFromASCII("str22");
79     constpool->SetObjectToCache(thread, 0, funcFunc.GetTaggedValue());
80     constpool->SetObjectToCache(thread, 1, dateFunc.GetTaggedValue());
81     constpool->SetObjectToCache(thread, 2, str1.GetTaggedValue());
82     constpool->SetObjectToCache(thread, 3, numberFunc.GetTaggedValue());
83     constpool->SetObjectToCache(thread, 4, str2.GetTaggedValue());
84     constpool->SetObjectToCache(thread, 5, str1.GetTaggedValue());
85 
86     CString fileName = "snapshot";
87     Snapshot snapshotSerialize(ecmaVm);
88     // serialize
89     snapshotSerialize.Serialize(*constpool, nullptr, fileName);
90     // deserialize
91     Snapshot snapshotDeserialize(ecmaVm);
92     snapshotDeserialize.Deserialize(SnapshotType::VM_ROOT, fileName);
93 
94     auto beginRegion = const_cast<Heap *>(ecmaVm->GetHeap())->GetOldSpace()->GetCurrentRegion();
95     auto constpool1 = reinterpret_cast<ConstantPool *>(beginRegion->GetBegin());
96     EXPECT_EQ(constpool->GetClass()->SizeFromJSHClass(*constpool),
97               constpool1->GetClass()->SizeFromJSHClass(constpool1));
98     EXPECT_TRUE(constpool1->GetObjectFromCache(0).IsJSFunction());
99     EXPECT_TRUE(constpool1->GetObjectFromCache(1).IsJSFunction());
100     EXPECT_TRUE(constpool1->GetObjectFromCache(3).IsJSFunction());
101     EcmaString *str11 = reinterpret_cast<EcmaString *>(constpool1->Get(2).GetTaggedObject());
102     EcmaString *str22 = reinterpret_cast<EcmaString *>(constpool1->Get(4).GetTaggedObject());
103     EcmaString *str33 = reinterpret_cast<EcmaString *>(constpool1->Get(5).GetTaggedObject());
104     EXPECT_EQ(std::strcmp(EcmaStringAccessor(str11).ToCString().c_str(), "str11"), 0);
105     EXPECT_EQ(std::strcmp(EcmaStringAccessor(str22).ToCString().c_str(), "str22"), 0);
106     EXPECT_EQ(std::strcmp(EcmaStringAccessor(str33).ToCString().c_str(), "str11"), 0);
107     std::remove(fileName.c_str());
108 }
109 
HWTEST_F_L0(SnapshotTest,SerializeDifferentSpace)110 HWTEST_F_L0(SnapshotTest, SerializeDifferentSpace)
111 {
112     auto factory = ecmaVm->GetFactory();
113     JSHandle<ConstantPool> constpool = factory->NewConstantPool(400);
114     for (int i = 0; i < 100; i++) {
115         JSHandle<TaggedArray> array = factory->NewTaggedArray(10, JSTaggedValue::Hole(), MemSpaceType::SEMI_SPACE);
116         constpool->SetObjectToCache(thread, i, array.GetTaggedValue());
117     }
118     for (int i = 0; i < 100; i++) {
119         JSHandle<TaggedArray> array = factory->NewTaggedArray(10, JSTaggedValue::Hole(), MemSpaceType::OLD_SPACE);
120         constpool->SetObjectToCache(thread, i + 100, array.GetTaggedValue());
121     }
122     for (int i = 0; i < 100; i++) {
123         JSHandle<MachineCode> codeObj = factory->NewMachineCodeObject(0, nullptr);
124         constpool->SetObjectToCache(thread, i + 200, codeObj.GetTaggedValue());
125     }
126     for (int i = 0; i < 100; i++) {
127         JSHandle<ConstantPool> constpool1 = factory->NewConstantPool(10);
128         constpool->SetObjectToCache(thread, i + 300, constpool1.GetTaggedValue());
129     }
130 
131     CString fileName = "snapshot";
132     Snapshot snapshotSerialize(ecmaVm);
133     // serialize
134     snapshotSerialize.Serialize(*constpool, nullptr, fileName);
135     // deserialize
136     Snapshot snapshotDeserialize(ecmaVm);
137     snapshotDeserialize.Deserialize(SnapshotType::VM_ROOT, fileName);
138 
139     auto beginRegion = const_cast<Heap *>(ecmaVm->GetHeap())->GetOldSpace()->GetCurrentRegion();
140     auto constpool1 = reinterpret_cast<ConstantPool *>(beginRegion->GetBegin());
141     EXPECT_EQ(constpool->GetClass()->SizeFromJSHClass(*constpool),
142               constpool1->GetClass()->SizeFromJSHClass(constpool1));
143     EXPECT_TRUE(constpool1->GetObjectFromCache(0).IsTaggedArray());
144     EXPECT_TRUE(constpool1->GetObjectFromCache(100).IsTaggedArray());
145     EXPECT_TRUE(constpool1->GetObjectFromCache(200).IsMachineCodeObject());
146     EXPECT_TRUE(constpool1->GetObjectFromCache(300).IsTaggedArray());
147     auto obj1 = constpool1->GetObjectFromCache(0).GetTaggedObject();
148     EXPECT_TRUE(Region::ObjectAddressToRange(obj1)->InOldSpace());
149     auto obj2 = constpool1->GetObjectFromCache(100).GetTaggedObject();
150     EXPECT_TRUE(Region::ObjectAddressToRange(obj2)->InOldSpace());
151     auto obj3 = constpool1->GetObjectFromCache(200).GetTaggedObject();
152     auto region = Region::ObjectAddressToRange(obj3);
153     EXPECT_TRUE(region->InMachineCodeSpace());
154 
155     std::remove(fileName.c_str());
156 }
157 
HWTEST_F_L0(SnapshotTest,SerializeMultiFile)158 HWTEST_F_L0(SnapshotTest, SerializeMultiFile)
159 {
160     auto factory = ecmaVm->GetFactory();
161     JSHandle<ConstantPool> constpool1 = factory->NewConstantPool(400);
162     JSHandle<ConstantPool> constpool2 = factory->NewConstantPool(400);
163     for (int i = 0; i < 100; i++) {
164         JSHandle<TaggedArray> array = factory->NewTaggedArray(10, JSTaggedValue::Hole(), MemSpaceType::SEMI_SPACE);
165         constpool1->SetObjectToCache(thread, i, array.GetTaggedValue());
166         constpool2->SetObjectToCache(thread, i, array.GetTaggedValue());
167     }
168     for (int i = 0; i < 100; i++) {
169         JSHandle<TaggedArray> array = factory->NewTaggedArray(10, JSTaggedValue::Hole(), MemSpaceType::OLD_SPACE);
170         constpool1->SetObjectToCache(thread, i + 100, array.GetTaggedValue());
171         constpool2->SetObjectToCache(thread, i + 100, array.GetTaggedValue());
172     }
173     for (int i = 0; i < 100; i++) {
174         JSHandle<MachineCode> codeObj = factory->NewMachineCodeObject(0, nullptr);
175         constpool1->SetObjectToCache(thread, i + 200, codeObj.GetTaggedValue());
176         constpool2->SetObjectToCache(thread, i + 200, codeObj.GetTaggedValue());
177     }
178     for (int i = 0; i < 100; i++) {
179         JSHandle<ConstantPool> constpool3 = factory->NewConstantPool(10);
180         constpool1->SetObjectToCache(thread, i + 300, constpool3.GetTaggedValue());
181         constpool2->SetObjectToCache(thread, i + 300, constpool3.GetTaggedValue());
182     }
183 
184     CString fileName1 = "snapshot1";
185     CString fileName2 = "snapshot2";
186     Snapshot snapshotSerialize(ecmaVm);
187     // serialize
188     snapshotSerialize.Serialize(*constpool1, nullptr, fileName1);
189     snapshotSerialize.Serialize(*constpool2, nullptr, fileName2);
190     // deserialize
191     Snapshot snapshotDeserialize(ecmaVm);
192     snapshotDeserialize.Deserialize(SnapshotType::VM_ROOT, fileName1);
193     snapshotDeserialize.Deserialize(SnapshotType::VM_ROOT, fileName2);
194 
195     auto beginRegion = const_cast<Heap *>(ecmaVm->GetHeap())->GetOldSpace()->GetCurrentRegion();
196     auto constpool = reinterpret_cast<ConstantPool *>(beginRegion->GetBegin());
197     EXPECT_TRUE(constpool->GetObjectFromCache(0).IsTaggedArray());
198     EXPECT_TRUE(constpool->GetObjectFromCache(100).IsTaggedArray());
199     EXPECT_TRUE(constpool->GetObjectFromCache(200).IsMachineCodeObject());
200     auto obj1 = constpool->GetObjectFromCache(0).GetTaggedObject();
201     EXPECT_TRUE(Region::ObjectAddressToRange(obj1)->InOldSpace());
202     auto obj2 = constpool->GetObjectFromCache(100).GetTaggedObject();
203     EXPECT_TRUE(Region::ObjectAddressToRange(obj2)->InOldSpace());
204     auto obj3 = constpool->GetObjectFromCache(200).GetTaggedObject();
205     auto region = Region::ObjectAddressToRange(obj3);
206     EXPECT_TRUE(region->InMachineCodeSpace());
207 
208     std::remove(fileName1.c_str());
209     std::remove(fileName2.c_str());
210 }
211 
HWTEST_F_L0(SnapshotTest,SerializeBuiltins)212 HWTEST_F_L0(SnapshotTest, SerializeBuiltins)
213 {
214     // remove builtins.snapshot file first if exist
215     CString fileName = "builtins.snapshot";
216     std::remove(fileName.c_str());
217     // generate builtins.snapshot file
218     JSRuntimeOptions options1;
219     options1.SetArkProperties(ArkProperties::ENABLE_SNAPSHOT_SERIALIZE);
220     EcmaVM *ecmaVm1 = JSNApi::CreateEcmaVM(options1);
221     JSNApi::DestroyJSVM(ecmaVm1);
222 
223     // create EcmaVM use builtins deserialzie
224     JSRuntimeOptions options2;
225     options2.SetArkProperties(ArkProperties::ENABLE_SNAPSHOT_DESERIALIZE);
226     EcmaVM *ecmaVm2 = JSNApi::CreateEcmaVM(options2);
227     EXPECT_TRUE(ecmaVm2->GetGlobalEnv()->GetClass()->GetObjectType() == JSType::GLOBAL_ENV);
228     auto globalConst = const_cast<GlobalEnvConstants *>(ecmaVm2->GetJSThread()->GlobalConstants());
229     size_t hclassEndIndex = static_cast<size_t>(ConstantIndex::UNDEFINED_INDEX);
230     size_t hclassIndex = 0;
231     globalConst->VisitRangeSlot([&hclassIndex, &hclassEndIndex]([[maybe_unused]]Root type,
232                                                                 ObjectSlot start, ObjectSlot end) {
233         while (start < end) {
234             JSTaggedValue object(start.GetTaggedType());
235             start++;
236             if (hclassIndex < hclassEndIndex) {
237                 EXPECT_TRUE(object.IsJSHClass());
238             }
239             hclassIndex++;
240         }
241     });
242     JSNApi::DestroyJSVM(ecmaVm2);
243 
244     std::remove(fileName.c_str());
245 }
246 
HWTEST_F_L0(SnapshotTest,SerializeHugeObject)247 HWTEST_F_L0(SnapshotTest, SerializeHugeObject)
248 {
249     auto factory = ecmaVm->GetFactory();
250     auto env = ecmaVm->GetGlobalEnv();
251 
252     JSHandle<TaggedArray> array1 = factory->NewTaggedArray(300 * 1024 / 8);
253     JSHandle<TaggedArray> array2 = factory->NewTaggedArray(300 * 1024 / 8);
254     JSHandle<TaggedArray> array3 = factory->NewTaggedArray(100);
255 
256     JSHandle<JSFunction> funcFunc(env->GetFunctionFunction());
257     JSHandle<JSFunction> dateFunc(env->GetDateFunction());
258     JSHandle<JSFunction> numberFunc(env->GetNumberFunction());
259     array1->Set(thread, 0, array2.GetTaggedValue());
260     array1->Set(thread, 1, funcFunc.GetTaggedValue());
261     array1->Set(thread, 2, dateFunc.GetTaggedValue());
262     array1->Set(thread, 3, numberFunc.GetTaggedValue());
263     array2->Set(thread, 0, array3.GetTaggedValue());
264     array2->Set(thread, 1, funcFunc.GetTaggedValue());
265     array2->Set(thread, 2, dateFunc.GetTaggedValue());
266     array2->Set(thread, 3, numberFunc.GetTaggedValue());
267 
268     CString fileName = "snapshot";
269     Snapshot snapshotSerialize(ecmaVm);
270     // serialize
271     snapshotSerialize.Serialize(*array1, nullptr, fileName);
272     // deserialize
273     Snapshot snapshotDeserialize(ecmaVm);
274     snapshotDeserialize.Deserialize(SnapshotType::VM_ROOT, fileName);
275 
276     auto lastRegion = const_cast<Heap *>(ecmaVm->GetHeap())->GetHugeObjectSpace()->GetCurrentRegion();
277     auto array4 = reinterpret_cast<TaggedArray *>(lastRegion->GetBegin());
278     EXPECT_TRUE(array4->Get(0).IsTaggedArray());
279     EXPECT_TRUE(array4->Get(1).IsJSFunction());
280     EXPECT_TRUE(array4->Get(2).IsJSFunction());
281     EXPECT_TRUE(array4->Get(3).IsJSFunction());
282     std::remove(fileName.c_str());
283 }
284 
HWTEST_F_L0(SnapshotTest,VersionTest)285 HWTEST_F_L0(SnapshotTest, VersionTest)
286 {
287     base::FileHeader::VersionType version = {4, 3, 2, 1};
288     uint32_t versionNumber = 0x04030201U;
289     EXPECT_EQ(version, base::FileHeader::ToVersion(versionNumber));
290     EXPECT_EQ(versionNumber, base::FileHeader::ToVersionNumber(version));
291 }
292 }  // namespace panda::test
293