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 "assembler/assembly-emitter.h"
17 #include "assembler/assembly-parser.h"
18 #include "libpandafile/class_data_accessor-inl.h"
19 #include "libziparchive/zip_archive.h"
20
21 #include "ecmascript/global_env.h"
22 #include "ecmascript/jspandafile/abc_buffer_cache.h"
23 #include "ecmascript/jspandafile/js_pandafile.h"
24 #include "ecmascript/jspandafile/js_pandafile_manager.h"
25 #include "ecmascript/jspandafile/program_object.h"
26 #include "ecmascript/tests/test_helper.h"
27
28 using namespace panda::ecmascript;
29 using namespace panda::panda_file;
30 using namespace panda::pandasm;
31
32 namespace panda::test {
33 class JSPandaFileManagerTest : 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 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
48 }
49
TearDown()50 void TearDown() override
51 {
52 TestHelper::DestroyEcmaVMWithScope(instance, scope);
53 }
54
55 EcmaVM *instance {nullptr};
56 EcmaHandleScope *scope {nullptr};
57 JSThread *thread {nullptr};
58 };
59
HWTEST_F_L0(JSPandaFileManagerTest,GetInstance)60 HWTEST_F_L0(JSPandaFileManagerTest, GetInstance)
61 {
62 JSPandaFileManager *manager = JSPandaFileManager::GetInstance();
63 EXPECT_TRUE(manager != nullptr);
64 }
65
HWTEST_F_L0(JSPandaFileManagerTest,NewJSPandaFile)66 HWTEST_F_L0(JSPandaFileManagerTest, NewJSPandaFile)
67 {
68 Parser parser;
69 std::string fileName = "__JSPandaFileManagerTest.pa";
70 const char *source = R"(
71 .function void foo() {}
72 )";
73 auto res = parser.Parse(source, fileName);
74 EXPECT_EQ(parser.ShowError().err, Error::ErrorType::ERR_NONE);
75
76 std::unique_ptr<const File> pfPtr = pandasm::AsmEmitter::Emit(res.Value());
77 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
78 std::shared_ptr<JSPandaFile> pf = pfManager->NewJSPandaFile(pfPtr.release(), CString(fileName.c_str()));
79 EXPECT_TRUE(pf != nullptr);
80
81 auto expectFileName = pf->GetJSPandaFileDesc();
82 EXPECT_STREQ(expectFileName.c_str(), "__JSPandaFileManagerTest.pa");
83 remove(fileName.c_str());
84 pfManager->RemoveJSPandaFile(pf.get());
85 }
86
HWTEST_F_L0(JSPandaFileManagerTest,OpenJSPandaFile)87 HWTEST_F_L0(JSPandaFileManagerTest, OpenJSPandaFile)
88 {
89 const char *filename = "__JSPandaFileManagerTest.pa";
90 const char *data = R"(
91 .function void foo() {}
92 )";
93 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
94 std::shared_ptr<JSPandaFile> ojspf = pfManager->OpenJSPandaFile(filename);
95 EXPECT_TRUE(ojspf == nullptr);
96
97 Parser parser;
98 auto res = parser.Parse(data);
99 EXPECT_TRUE(pandasm::AsmEmitter::Emit(filename, res.Value()));
100
101 ojspf = pfManager->OpenJSPandaFile(filename);
102 EXPECT_TRUE(ojspf != nullptr);
103 EXPECT_STREQ(ojspf->GetJSPandaFileDesc().c_str(), "__JSPandaFileManagerTest.pa");
104 pfManager->RemoveJSPandaFile(ojspf.get());
105
106 remove(filename);
107 ojspf = pfManager->OpenJSPandaFile(filename);
108 EXPECT_TRUE(ojspf == nullptr);
109 }
110
HWTEST_F_L0(JSPandaFileManagerTest,Add_Find_Remove_JSPandaFile)111 HWTEST_F_L0(JSPandaFileManagerTest, Add_Find_Remove_JSPandaFile)
112 {
113 const char *filename1 = "__JSPandaFileManagerTest1.pa";
114 const char *filename2 = "__JSPandaFileManagerTest2.pa";
115 const char *data = R"(
116 .function void foo() {}
117 )";
118 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
119 Parser parser;
120 auto res = parser.Parse(data);
121 std::unique_ptr<const File> pfPtr1 = pandasm::AsmEmitter::Emit(res.Value());
122 std::unique_ptr<const File> pfPtr2 = pandasm::AsmEmitter::Emit(res.Value());
123 std::shared_ptr<JSPandaFile> pf1 = pfManager->NewJSPandaFile(pfPtr1.release(), CString(filename1));
124 std::shared_ptr<JSPandaFile> pf2 = pfManager->NewJSPandaFile(pfPtr2.release(), CString(filename2));
125 pfManager->AddJSPandaFile(pf1);
126 pfManager->AddJSPandaFile(pf2);
127 std::shared_ptr<JSPandaFile> foundPf1 = pfManager->FindJSPandaFile(filename1);
128 std::shared_ptr<JSPandaFile> foundPf2 = pfManager->FindJSPandaFile(filename2);
129 EXPECT_STREQ(foundPf1->GetJSPandaFileDesc().c_str(), "__JSPandaFileManagerTest1.pa");
130 EXPECT_STREQ(foundPf2->GetJSPandaFileDesc().c_str(), "__JSPandaFileManagerTest2.pa");
131
132 pfManager->RemoveJSPandaFile(pf1.get());
133 pfManager->RemoveJSPandaFile(pf2.get());
134 std::shared_ptr<JSPandaFile> afterRemovePf1 = pfManager->FindJSPandaFile(filename1);
135 std::shared_ptr<JSPandaFile> afterRemovePf2 = pfManager->FindJSPandaFile(filename2);
136 EXPECT_EQ(afterRemovePf1, nullptr);
137 EXPECT_EQ(afterRemovePf2, nullptr);
138 }
139
HWTEST_F_L0(JSPandaFileManagerTest,MultiEcmaVM_Add_Find_Remove_JSPandaFile)140 HWTEST_F_L0(JSPandaFileManagerTest, MultiEcmaVM_Add_Find_Remove_JSPandaFile)
141 {
142 const char *filename1 = "__JSPandaFileManagerTest1.pa";
143 const char *filename2 = "__JSPandaFileManagerTest2.pa";
144 const char *data = R"(
145 .function void foo() {}
146 )";
147 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
148 Parser parser;
149 auto res = parser.Parse(data);
150 std::unique_ptr<const File> pfPtr1 = pandasm::AsmEmitter::Emit(res.Value());
151 std::unique_ptr<const File> pfPtr2 = pandasm::AsmEmitter::Emit(res.Value());
152 std::shared_ptr<JSPandaFile> pf1 = pfManager->NewJSPandaFile(pfPtr1.release(), CString(filename1));
153 std::shared_ptr<JSPandaFile> pf2 = pfManager->NewJSPandaFile(pfPtr2.release(), CString(filename2));
154 pfManager->AddJSPandaFile(pf1);
155 pfManager->AddJSPandaFile(pf2);
156
157 EcmaContext *context = instance->GetJSThread()->GetCurrentEcmaContext();
158 JSHandle<ConstantPool> constpool1 = instance->GetFactory()->NewSConstantPool(1);
159 JSHandle<ConstantPool> constpool2 = instance->GetFactory()->NewSConstantPool(2);
160 constpool1 = context->AddOrUpdateConstpool(pf1.get(), constpool1, 0);
161 constpool2 = context->AddOrUpdateConstpool(pf2.get(), constpool2, 0);
162
163 std::thread t1([&]() {
164 EcmaVM *instance1;
165 EcmaHandleScope *scope1;
166 JSThread *thread1;
167 TestHelper::CreateEcmaVMWithScope(instance1, thread1, scope1);
168 std::shared_ptr<JSPandaFile> loadedPf1 = pfManager->LoadJSPandaFile(
169 thread1, filename1, JSPandaFile::ENTRY_MAIN_FUNCTION, false, ExecuteTypes::STATIC);
170 EXPECT_TRUE(pf1 == loadedPf1);
171 EXPECT_TRUE(instance1->GetJSThread()->GetCurrentEcmaContext()->HasCachedConstpool(pf1.get()));
172 TestHelper::DestroyEcmaVMWithScope(instance1, scope1); // Remove 'instance1' when ecmaVM destruct.
173 });
174 {
175 ThreadSuspensionScope suspensionScope(thread);
176 t1.join();
177 }
178
179 std::shared_ptr<JSPandaFile> foundPf1 = pfManager->FindJSPandaFile(filename1);
180 EXPECT_TRUE(foundPf1 != nullptr);
181
182 pfManager->RemoveJSPandaFile(pf1.get());
183 pfManager->RemoveJSPandaFile(pf2.get());
184 std::shared_ptr<JSPandaFile> afterRemovePf1 = pfManager->FindJSPandaFile(filename1);
185 std::shared_ptr<JSPandaFile> afterRemovePf2 = pfManager->FindJSPandaFile(filename2);
186 EXPECT_EQ(afterRemovePf1, nullptr);
187 EXPECT_EQ(afterRemovePf2, nullptr);
188 }
189
CreateJSPandaFileAndConstpool(EcmaVM * vm)190 void CreateJSPandaFileAndConstpool(EcmaVM *vm)
191 {
192 const char *filename = "__JSPandaFileManagerTest1.pa";
193 const char *data = R"(
194 .function void foo() {}
195 )";
196 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
197 Parser parser;
198 auto res = parser.Parse(data);
199 std::unique_ptr<const File> pfPtr = pandasm::AsmEmitter::Emit(res.Value());
200 std::shared_ptr<JSPandaFile> pf = pfManager->NewJSPandaFile(pfPtr.release(), CString(filename));
201 pfManager->AddJSPandaFile(pf);
202
203 [[maybe_unused]] EcmaHandleScope handleScope(vm->GetJSThread());
204 JSHandle<ConstantPool> constpool = vm->GetFactory()->NewSConstantPool(1);
205 auto context = vm->GetJSThread()->GetCurrentEcmaContext();
206 constpool = context->AddOrUpdateConstpool(pf.get(), constpool, 0);
207 JSHandle<ConstantPool> newConstpool = vm->GetFactory()->NewConstantPool(1);
208 context->SetUnsharedConstpool(constpool, newConstpool.GetTaggedValue());
209 }
210
HWTEST_F_L0(JSPandaFileManagerTest,GC_Add_Find_Remove_JSPandaFile)211 HWTEST_F_L0(JSPandaFileManagerTest, GC_Add_Find_Remove_JSPandaFile)
212 {
213 const char *filename = "__JSPandaFileManagerTest1.pa";
214 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
215
216 CreateJSPandaFileAndConstpool(instance);
217 // Remove 'instance' and JSPandafile when trigger GC.
218 SharedHeap::GetInstance()->CollectGarbage<TriggerGCType::SHARED_GC, GCReason::OTHER>(instance->GetJSThread());
219 SharedHeap::GetInstance()->CollectGarbage<TriggerGCType::SHARED_GC, GCReason::OTHER>(instance->GetJSThread());
220 std::shared_ptr<JSPandaFile> afterRemovePf = pfManager->FindJSPandaFile(filename);
221 EXPECT_EQ(afterRemovePf, nullptr);
222 }
223
HWTEST_F_L0(JSPandaFileManagerTest,LoadJSPandaFile)224 HWTEST_F_L0(JSPandaFileManagerTest, LoadJSPandaFile)
225 {
226 const char *filename1 = "__JSPandaFileManagerTest1.pa";
227 const char *filename2 = "__JSPandaFileManagerTest2.pa";
228 const char *filename3 = "__JSPandaFileManagerTest3.abc";
229 const char *data = R"(
230 .function void foo() {}
231 )";
232 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
233 Parser parser;
234 auto res = parser.Parse(data);
235 std::unique_ptr<const File> pfPtr1 = pandasm::AsmEmitter::Emit(res.Value());
236 std::unique_ptr<const File> pfPtr2 = pandasm::AsmEmitter::Emit(res.Value());
237 std::unique_ptr<const File> pfPtr3 = pandasm::AsmEmitter::Emit(res.Value());
238 std::shared_ptr<JSPandaFile> pf1 = pfManager->NewJSPandaFile(pfPtr1.release(), CString(filename1));
239 std::shared_ptr<JSPandaFile> pf2 = pfManager->NewJSPandaFile(pfPtr2.release(), CString(filename2));
240 std::shared_ptr<JSPandaFile> pf3 = pfManager->NewJSPandaFile(pfPtr3.release(), CString(filename3));
241 pfManager->AddJSPandaFile(pf1);
242 pfManager->AddJSPandaFile(pf2);
243 pfManager->AddJSPandaFile(pf3);
244 std::shared_ptr<JSPandaFile> loadedPf1 =
245 pfManager->LoadJSPandaFile(thread, filename1, JSPandaFile::ENTRY_MAIN_FUNCTION);
246 std::shared_ptr<JSPandaFile> loadedPf2 =
247 pfManager->LoadJSPandaFile(thread, filename2, JSPandaFile::ENTRY_MAIN_FUNCTION, (void *)data, sizeof(data));
248 std::shared_ptr<JSPandaFile> loadedPf3 =
249 pfManager->LoadJSPandaFile(thread, filename3, JSPandaFile::ENTRY_MAIN_FUNCTION, (void *)data, sizeof(data));
250 EXPECT_TRUE(loadedPf1 != nullptr);
251 EXPECT_TRUE(loadedPf2 != nullptr);
252 EXPECT_TRUE(loadedPf3 != nullptr);
253 EXPECT_TRUE(pf1 == loadedPf1);
254 EXPECT_TRUE(pf2 == loadedPf2);
255 EXPECT_TRUE(pf3 == loadedPf3);
256 EXPECT_STREQ(loadedPf1->GetJSPandaFileDesc().c_str(), "__JSPandaFileManagerTest1.pa");
257 EXPECT_STREQ(loadedPf2->GetJSPandaFileDesc().c_str(), "__JSPandaFileManagerTest2.pa");
258 EXPECT_STREQ(loadedPf3->GetJSPandaFileDesc().c_str(), "__JSPandaFileManagerTest3.abc");
259
260 pfManager->RemoveJSPandaFile(pf1.get());
261 pfManager->RemoveJSPandaFile(pf2.get());
262 pfManager->RemoveJSPandaFile(pf3.get());
263 }
264
HWTEST_F_L0(JSPandaFileManagerTest,GenerateProgram)265 HWTEST_F_L0(JSPandaFileManagerTest, GenerateProgram)
266 {
267 Parser parser;
268 auto vm = thread->GetEcmaVM();
269 const char *filename = "__JSPandaFileManagerTest.pa";
270 const uint8_t *typeDesc = utf::CStringAsMutf8("L_GLOBAL;");
271 const char *data = R"(
272 .function void foo() {}
273 )";
274 auto res = parser.Parse(data);
275 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
276 std::unique_ptr<const File> pfPtr = pandasm::AsmEmitter::Emit(res.Value());
277 std::shared_ptr<JSPandaFile> pf = pfManager->NewJSPandaFile(pfPtr.release(), CString(filename));
278 const File *file = pf->GetPandaFile();
279 File::EntityId classId = file->GetClassId(typeDesc);
280 ClassDataAccessor cda(*file, classId);
281 std::vector<File::EntityId> methodId {};
282 cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) {
283 methodId.push_back(mda.GetMethodId());
284 });
285 pf->UpdateMainMethodIndex(methodId[0].GetOffset());
286 MethodLiteral *method = new MethodLiteral(methodId[0]);
287 pf->SetMethodLiteralToMap(method);
288 pfManager->AddJSPandaFile(pf);
289
290 JSHandle<ecmascript::Program> program = pfManager->GenerateProgram(vm, pf.get(), JSPandaFile::ENTRY_FUNCTION_NAME);
291 JSHandle<JSFunction> mainFunc(thread, program->GetMainFunction());
292 JSHandle<JSTaggedValue> funcName = JSFunction::GetFunctionName(thread, JSHandle<JSFunctionBase>(mainFunc));
293 EXPECT_STREQ(EcmaStringAccessor(JSHandle<EcmaString>::Cast(funcName)).ToCString().c_str(), "foo");
294
295 pfManager->RemoveJSPandaFile(pf.get());
296 }
297
HWTEST_F_L0(JSPandaFileManagerTest,GetJSPtExtractor)298 HWTEST_F_L0(JSPandaFileManagerTest, GetJSPtExtractor)
299 {
300 const char *filename = "__JSPandaFileManagerTest.pa";
301 const char *data = R"(
302 .function void foo() {}
303 )";
304 Parser parser;
305 auto res = parser.Parse(data);
306 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
307 std::unique_ptr<const File> pfPtr = pandasm::AsmEmitter::Emit(res.Value());
308 std::shared_ptr<JSPandaFile> pf = pfManager->NewJSPandaFile(pfPtr.release(), CString(filename));
309 pfManager->AddJSPandaFile(pf);
310 DebugInfoExtractor *extractor = pfManager->GetJSPtExtractor(pf.get());
311 EXPECT_TRUE(extractor != nullptr);
312
313 pfManager->RemoveJSPandaFile(pf.get());
314 }
315
HWTEST_F_L0(JSPandaFileManagerTest,EnumerateJSPandaFiles)316 HWTEST_F_L0(JSPandaFileManagerTest, EnumerateJSPandaFiles)
317 {
318 const char *filename1 = "__JSPandaFileManagerTest3.pa";
319 const char *filename2 = "__JSPandaFileManagerTest4.pa";
320 const char *data = R"(
321 .function void foo() {}
322 )";
323 Parser parser;
324 auto res = parser.Parse(data);
325 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
326 std::unique_ptr<const File> pfPtr1 = pandasm::AsmEmitter::Emit(res.Value());
327 std::unique_ptr<const File> pfPtr2 = pandasm::AsmEmitter::Emit(res.Value());
328 std::shared_ptr<JSPandaFile> pf1 = pfManager->NewJSPandaFile(pfPtr1.release(), CString(filename1));
329 std::shared_ptr<JSPandaFile> pf2 = pfManager->NewJSPandaFile(pfPtr2.release(), CString(filename2));
330 pfManager->AddJSPandaFile(pf1);
331 pfManager->AddJSPandaFile(pf2);
332 std::vector<CString> descList{};
333 int count = 0;
334 pfManager->EnumerateJSPandaFiles([&](const std::shared_ptr<JSPandaFile> &file) -> bool {
335 auto desc = file->GetJSPandaFileDesc();
336 std::cout << "desc:" << desc << std::endl;
337 descList.push_back(desc);
338 count++;
339 return true;
340 });
341 EXPECT_EQ(count, 2); // 2 : test number of files
342 // Sort by the hash value of the element, the output is unordered
343 EXPECT_STREQ(descList[0].c_str(), "__JSPandaFileManagerTest4.pa");
344 EXPECT_STREQ(descList[1].c_str(), "__JSPandaFileManagerTest3.pa");
345
346 pfManager->RemoveJSPandaFile(pf1.get());
347 pfManager->RemoveJSPandaFile(pf2.get());
348 }
349
HWTEST_F_L0(JSPandaFileManagerTest,CheckFilePath)350 HWTEST_F_L0(JSPandaFileManagerTest, CheckFilePath)
351 {
352 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
353 const char *fileName = "__JSPandaFileManagerTest3.abc";
354 const char *data = R"(
355 .function void foo() {}
356 )";
357 Parser parser;
358 auto res = parser.Parse(data);
359 std::unique_ptr<const File> pfPtr = pandasm::AsmEmitter::Emit(res.Value());
360 std::shared_ptr<JSPandaFile> pf = pfManager->NewJSPandaFile(pfPtr.release(), CString(fileName));
361 pfManager->AddJSPandaFile(pf);
362 bool result = pfManager->CheckFilePath(thread, fileName);
363 EXPECT_TRUE(result);
364 pfManager->RemoveJSPandaFile(pf.get());
365 }
366
HWTEST_F_L0(JSPandaFileManagerTest,GetJSPandaFileByBufferFiles)367 HWTEST_F_L0(JSPandaFileManagerTest, GetJSPandaFileByBufferFiles)
368 {
369 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
370 const char *fileName = "__JSPandaFileManagerTest3.abc";
371 const char *data = R"(
372 .function void foo() {}
373 )";
374 Parser parser;
375 auto res = parser.Parse(data);
376 std::unique_ptr<const File> pfPtr = pandasm::AsmEmitter::Emit(res.Value());
377 std::shared_ptr<JSPandaFile> pf = pfManager->NewJSPandaFile(pfPtr.release(), CString(fileName));
378 std::shared_ptr<JSPandaFile> jsPandaFile;
379 pfManager->AddJSPandaFile(pf);
380 AbcBufferCache *abcBufferCache = thread->GetCurrentEcmaContext()->GetAbcBufferCache();
381 abcBufferCache->AddAbcBufferToCache(CString(fileName), (void *)data, sizeof(data), AbcBufferType::NORMAL_BUFFER);
382 AbcBufferInfo bufferInfo = abcBufferCache->FindJSPandaFileInAbcBufferCache(CString(fileName));
383 EXPECT_TRUE(bufferInfo.buffer_ != nullptr);
384 abcBufferCache->DeleteAbcBufferFromCache(CString(fileName));
385 jsPandaFile = pfManager->LoadJSPandaFile(thread, CString(fileName), "");
386 EXPECT_TRUE(jsPandaFile != nullptr);
387 }
388 } // namespace panda::test
389