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