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 28using namespace panda::ecmascript; 29using namespace panda::panda_file; 30using namespace panda::pandasm; 31 32namespace panda::test { 33class JSPandaFileManagerTest : public testing::Test { 34public: 35 static void SetUpTestCase() 36 { 37 GTEST_LOG_(INFO) << "SetUpTestCase"; 38 } 39 40 static void TearDownTestCase() 41 { 42 GTEST_LOG_(INFO) << "TearDownCase"; 43 } 44 45 void SetUp() override 46 { 47 TestHelper::CreateEcmaVMWithScope(instance, thread, scope); 48 } 49 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 60HWTEST_F_L0(JSPandaFileManagerTest, GetInstance) 61{ 62 JSPandaFileManager *manager = JSPandaFileManager::GetInstance(); 63 EXPECT_TRUE(manager != nullptr); 64} 65 66HWTEST_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 87HWTEST_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 111HWTEST_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 140HWTEST_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 = 169 pfManager->LoadJSPandaFile(thread1, filename1, JSPandaFile::ENTRY_MAIN_FUNCTION); 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 190void 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 211HWTEST_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 224HWTEST_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 265HWTEST_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 298HWTEST_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 316HWTEST_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 350HWTEST_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 367HWTEST_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