• 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/ts_types/ts_manager.h"
28 
29 using namespace panda::ecmascript;
30 
31 namespace panda::test {
32 class SnapshotTest : public testing::Test {
33 public:
SetUpTestCase()34     static void SetUpTestCase()
35     {
36         GTEST_LOG_(INFO) << "SetUpTestCase";
37     }
38 
TearDownTestCase()39     static void TearDownTestCase()
40     {
41         GTEST_LOG_(INFO) << "TearDownCase";
42     }
43 
SetUp()44     void SetUp() override
45     {
46         JSRuntimeOptions options;
47         ecmaVm = JSNApi::CreateEcmaVM(options);
48         ASSERT_TRUE(ecmaVm != nullptr) << "Cannot create EcmaVM";
49         thread = ecmaVm->GetJSThread();
50         scope = new EcmaHandleScope(thread);
51     }
52 
TearDown()53     void TearDown() override
54     {
55         delete scope;
56         scope = nullptr;
57         ecmaVm->SetEnableForceGC(false);
58         thread->ClearException();
59         JSNApi::DestroyJSVM(ecmaVm);
60     }
61 
62     EcmaVM *ecmaVm {nullptr};
63     ecmascript::EcmaHandleScope *scope {nullptr};
64     JSThread *thread {nullptr};
65 };
66 
HWTEST_F_L0(SnapshotTest,SerializeConstPool)67 HWTEST_F_L0(SnapshotTest, SerializeConstPool)
68 {
69     auto factory = ecmaVm->GetFactory();
70     auto env = ecmaVm->GetGlobalEnv();
71 
72     JSHandle<ConstantPool> constpool = factory->NewConstantPool(6);
73     JSHandle<JSFunction> funcFunc(env->GetFunctionFunction());
74     JSHandle<JSFunction> dateFunc(env->GetDateFunction());
75     JSHandle<JSFunction> numberFunc(env->GetNumberFunction());
76     JSHandle<EcmaString> str1 = factory->NewFromASCII("str11");
77     JSHandle<EcmaString> str2 = factory->NewFromASCII("str22");
78     constpool->SetObjectToCache(thread, 0, funcFunc.GetTaggedValue());
79     constpool->SetObjectToCache(thread, 1, dateFunc.GetTaggedValue());
80     constpool->SetObjectToCache(thread, 2, str1.GetTaggedValue());
81     constpool->SetObjectToCache(thread, 3, numberFunc.GetTaggedValue());
82     constpool->SetObjectToCache(thread, 4, str2.GetTaggedValue());
83     constpool->SetObjectToCache(thread, 5, str1.GetTaggedValue());
84 
85     CString fileName = "snapshot";
86     Snapshot snapshotSerialize(ecmaVm);
87     // serialize
88     snapshotSerialize.Serialize(*constpool, nullptr, fileName);
89     // deserialize
90     Snapshot snapshotDeserialize(ecmaVm);
91     snapshotDeserialize.Deserialize(SnapshotType::VM_ROOT, fileName);
92 
93     auto beginRegion = const_cast<Heap *>(ecmaVm->GetHeap())->GetOldSpace()->GetCurrentRegion();
94     auto constpool1 = reinterpret_cast<ConstantPool *>(beginRegion->GetBegin());
95     EXPECT_EQ(constpool->GetClass()->SizeFromJSHClass(*constpool),
96               constpool1->GetClass()->SizeFromJSHClass(constpool1));
97     EXPECT_TRUE(constpool1->GetObjectFromCache(0).IsJSFunction());
98     EXPECT_TRUE(constpool1->GetObjectFromCache(1).IsJSFunction());
99     EXPECT_TRUE(constpool1->GetObjectFromCache(3).IsJSFunction());
100     EcmaString *str11 = reinterpret_cast<EcmaString *>(constpool1->Get(2).GetTaggedObject());
101     EcmaString *str22 = reinterpret_cast<EcmaString *>(constpool1->Get(4).GetTaggedObject());
102     EcmaString *str33 = reinterpret_cast<EcmaString *>(constpool1->Get(5).GetTaggedObject());
103     EXPECT_EQ(std::strcmp(EcmaStringAccessor(str11).ToCString().c_str(), "str11"), 0);
104     EXPECT_EQ(std::strcmp(EcmaStringAccessor(str22).ToCString().c_str(), "str22"), 0);
105     EXPECT_EQ(std::strcmp(EcmaStringAccessor(str33).ToCString().c_str(), "str11"), 0);
106     std::remove(fileName.c_str());
107 }
108 
HWTEST_F_L0(SnapshotTest,SerializeDifferentSpace)109 HWTEST_F_L0(SnapshotTest, SerializeDifferentSpace)
110 {
111     auto factory = ecmaVm->GetFactory();
112     JSHandle<ConstantPool> constpool = factory->NewConstantPool(400);
113     for (int i = 0; i < 100; i++) {
114         JSHandle<TaggedArray> array = factory->NewTaggedArray(10, JSTaggedValue::Hole(), MemSpaceType::SEMI_SPACE);
115         constpool->SetObjectToCache(thread, i, array.GetTaggedValue());
116     }
117     for (int i = 0; i < 100; i++) {
118         JSHandle<TaggedArray> array = factory->NewTaggedArray(10, JSTaggedValue::Hole(), MemSpaceType::OLD_SPACE);
119         constpool->SetObjectToCache(thread, i + 100, array.GetTaggedValue());
120     }
121     for (int i = 0; i < 100; i++) {
122         JSHandle<MachineCode> codeObj = factory->NewMachineCodeObject(0, nullptr);
123         constpool->SetObjectToCache(thread, i + 200, codeObj.GetTaggedValue());
124     }
125     for (int i = 0; i < 100; i++) {
126         JSHandle<ConstantPool> constpool1 = factory->NewConstantPool(10);
127         constpool->SetObjectToCache(thread, i + 300, constpool1.GetTaggedValue());
128     }
129 
130     CString fileName = "snapshot";
131     Snapshot snapshotSerialize(ecmaVm);
132     // serialize
133     snapshotSerialize.Serialize(*constpool, nullptr, fileName);
134     // deserialize
135     Snapshot snapshotDeserialize(ecmaVm);
136     snapshotDeserialize.Deserialize(SnapshotType::VM_ROOT, fileName);
137 
138     auto beginRegion = const_cast<Heap *>(ecmaVm->GetHeap())->GetOldSpace()->GetCurrentRegion();
139     auto constpool1 = reinterpret_cast<ConstantPool *>(beginRegion->GetBegin());
140     EXPECT_EQ(constpool->GetClass()->SizeFromJSHClass(*constpool),
141               constpool1->GetClass()->SizeFromJSHClass(constpool1));
142     EXPECT_TRUE(constpool1->GetObjectFromCache(0).IsTaggedArray());
143     EXPECT_TRUE(constpool1->GetObjectFromCache(100).IsTaggedArray());
144     EXPECT_TRUE(constpool1->GetObjectFromCache(200).IsMachineCodeObject());
145     EXPECT_TRUE(constpool1->GetObjectFromCache(300).IsTaggedArray());
146     auto obj1 = constpool1->GetObjectFromCache(0).GetTaggedObject();
147     EXPECT_TRUE(Region::ObjectAddressToRange(obj1)->InOldSpace());
148     auto obj2 = constpool1->GetObjectFromCache(100).GetTaggedObject();
149     EXPECT_TRUE(Region::ObjectAddressToRange(obj2)->InOldSpace());
150     auto obj3 = constpool1->GetObjectFromCache(200).GetTaggedObject();
151     auto region = Region::ObjectAddressToRange(obj3);
152     EXPECT_TRUE(region->InMachineCodeSpace());
153 
154     std::remove(fileName.c_str());
155 }
156 
HWTEST_F_L0(SnapshotTest,SerializeMultiFile)157 HWTEST_F_L0(SnapshotTest, SerializeMultiFile)
158 {
159     auto factory = ecmaVm->GetFactory();
160     JSHandle<ConstantPool> constpool1 = factory->NewConstantPool(400);
161     JSHandle<ConstantPool> constpool2 = factory->NewConstantPool(400);
162     for (int i = 0; i < 100; i++) {
163         JSHandle<TaggedArray> array = factory->NewTaggedArray(10, JSTaggedValue::Hole(), MemSpaceType::SEMI_SPACE);
164         constpool1->SetObjectToCache(thread, i, array.GetTaggedValue());
165         constpool2->SetObjectToCache(thread, i, array.GetTaggedValue());
166     }
167     for (int i = 0; i < 100; i++) {
168         JSHandle<TaggedArray> array = factory->NewTaggedArray(10, JSTaggedValue::Hole(), MemSpaceType::OLD_SPACE);
169         constpool1->SetObjectToCache(thread, i + 100, array.GetTaggedValue());
170         constpool2->SetObjectToCache(thread, i + 100, array.GetTaggedValue());
171     }
172     for (int i = 0; i < 100; i++) {
173         JSHandle<MachineCode> codeObj = factory->NewMachineCodeObject(0, nullptr);
174         constpool1->SetObjectToCache(thread, i + 200, codeObj.GetTaggedValue());
175         constpool2->SetObjectToCache(thread, i + 200, codeObj.GetTaggedValue());
176     }
177     for (int i = 0; i < 100; i++) {
178         JSHandle<ConstantPool> constpool3 = factory->NewConstantPool(10);
179         constpool1->SetObjectToCache(thread, i + 300, constpool3.GetTaggedValue());
180         constpool2->SetObjectToCache(thread, i + 300, constpool3.GetTaggedValue());
181     }
182 
183     CString fileName1 = "snapshot1";
184     CString fileName2 = "snapshot2";
185     Snapshot snapshotSerialize(ecmaVm);
186     // serialize
187     snapshotSerialize.Serialize(*constpool1, nullptr, fileName1);
188     snapshotSerialize.Serialize(*constpool2, nullptr, fileName2);
189     // deserialize
190     Snapshot snapshotDeserialize(ecmaVm);
191     snapshotDeserialize.Deserialize(SnapshotType::VM_ROOT, fileName1);
192     snapshotDeserialize.Deserialize(SnapshotType::VM_ROOT, fileName2);
193 
194     auto beginRegion = const_cast<Heap *>(ecmaVm->GetHeap())->GetOldSpace()->GetCurrentRegion();
195     auto constpool = reinterpret_cast<ConstantPool *>(beginRegion->GetBegin());
196     EXPECT_TRUE(constpool->GetObjectFromCache(0).IsTaggedArray());
197     EXPECT_TRUE(constpool->GetObjectFromCache(100).IsTaggedArray());
198     EXPECT_TRUE(constpool->GetObjectFromCache(200).IsMachineCodeObject());
199     auto obj1 = constpool->GetObjectFromCache(0).GetTaggedObject();
200     EXPECT_TRUE(Region::ObjectAddressToRange(obj1)->InOldSpace());
201     auto obj2 = constpool->GetObjectFromCache(100).GetTaggedObject();
202     EXPECT_TRUE(Region::ObjectAddressToRange(obj2)->InOldSpace());
203     auto obj3 = constpool->GetObjectFromCache(200).GetTaggedObject();
204     auto region = Region::ObjectAddressToRange(obj3);
205     EXPECT_TRUE(region->InMachineCodeSpace());
206 
207     std::remove(fileName1.c_str());
208     std::remove(fileName2.c_str());
209 }
210 
HWTEST_F_L0(SnapshotTest,SerializeBuiltins)211 HWTEST_F_L0(SnapshotTest, SerializeBuiltins)
212 {
213     // remove builtins.snapshot file first if exist
214     CString fileName = "builtins.snapshot";
215     std::remove(fileName.c_str());
216     // generate builtins.snapshot file
217     JSRuntimeOptions options1;
218     options1.SetArkProperties(ArkProperties::ENABLE_SNAPSHOT_SERIALIZE);
219     EcmaVM *ecmaVm1 = JSNApi::CreateEcmaVM(options1);
220     JSNApi::DestroyJSVM(ecmaVm1);
221 
222     // create EcmaVM use builtins deserialzie
223     JSRuntimeOptions options2;
224     options2.SetArkProperties(ArkProperties::ENABLE_SNAPSHOT_DESERIALIZE);
225     EcmaVM *ecmaVm2 = JSNApi::CreateEcmaVM(options2);
226     EXPECT_TRUE(ecmaVm2->GetGlobalEnv()->GetClass()->GetObjectType() == JSType::GLOBAL_ENV);
227     auto globalConst = const_cast<GlobalEnvConstants *>(ecmaVm2->GetJSThread()->GlobalConstants());
228     size_t hclassEndIndex = static_cast<size_t>(ConstantIndex::UNDEFINED_INDEX);
229     size_t hclassIndex = 0;
230     globalConst->VisitRangeSlot([&hclassIndex, &hclassEndIndex]([[maybe_unused]]Root type,
231                                                                 ObjectSlot start, ObjectSlot end) {
232         while (start < end) {
233             JSTaggedValue object(start.GetTaggedType());
234             start++;
235             if (hclassIndex < hclassEndIndex) {
236                 EXPECT_TRUE(object.IsJSHClass());
237             }
238             hclassIndex++;
239         }
240     });
241     JSNApi::DestroyJSVM(ecmaVm2);
242 
243     std::remove(fileName.c_str());
244 }
245 
HWTEST_F_L0(SnapshotTest,SerializeHugeObject)246 HWTEST_F_L0(SnapshotTest, SerializeHugeObject)
247 {
248     auto factory = ecmaVm->GetFactory();
249     auto env = ecmaVm->GetGlobalEnv();
250 
251     JSHandle<TaggedArray> array1 = factory->NewTaggedArray(300 * 1024 / 8);
252     JSHandle<TaggedArray> array2 = factory->NewTaggedArray(300 * 1024 / 8);
253 
254     JSHandle<JSFunction> funcFunc(env->GetFunctionFunction());
255     JSHandle<JSFunction> dateFunc(env->GetDateFunction());
256     JSHandle<JSFunction> numberFunc(env->GetNumberFunction());
257     array1->Set(thread, 0, array2.GetTaggedValue());
258     array1->Set(thread, 1, funcFunc.GetTaggedValue());
259     array1->Set(thread, 2, dateFunc.GetTaggedValue());
260     array1->Set(thread, 3, numberFunc.GetTaggedValue());
261 
262     CString fileName = "snapshot";
263     Snapshot snapshotSerialize(ecmaVm);
264     // serialize
265     snapshotSerialize.Serialize(*array1, nullptr, fileName);
266     // deserialize
267     Snapshot snapshotDeserialize(ecmaVm);
268     snapshotDeserialize.Deserialize(SnapshotType::VM_ROOT, fileName);
269 
270     auto beginRegion = const_cast<Heap *>(ecmaVm->GetHeap())->GetHugeObjectSpace()->GetFirstRegion();
271     auto array3 = reinterpret_cast<TaggedArray *>(beginRegion->GetBegin());
272     EXPECT_TRUE(array3->Get(0).IsTaggedArray());
273     EXPECT_TRUE(array3->Get(1).IsJSFunction());
274     EXPECT_TRUE(array3->Get(2).IsJSFunction());
275     EXPECT_TRUE(array3->Get(3).IsJSFunction());
276     std::remove(fileName.c_str());
277 }
278 }  // namespace panda::test
279