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 "gtest/gtest.h" 19#include "libpandabase/utils/utf.h" 20#include "libpandafile/class_data_accessor-inl.h" 21 22#include "ecmascript/mem/c_containers.h" 23#include "ecmascript/jspandafile/js_pandafile.h" 24#include "ecmascript/jspandafile/js_pandafile_manager.h" 25#include "ecmascript/tests/test_helper.h" 26 27using namespace panda::ecmascript; 28using namespace panda::panda_file; 29using namespace panda::pandasm; 30 31namespace panda::test { 32class JSPandaFileTest : public testing::Test { 33public: 34 static void SetUpTestCase() 35 { 36 GTEST_LOG_(INFO) << "SetUpTestCase"; 37 } 38 39 static void TearDownTestCase() 40 { 41 GTEST_LOG_(INFO) << "TearDownCase"; 42 } 43 44 void SetUp() override 45 { 46 TestHelper::CreateEcmaVMWithScope(instance, thread, scope); 47 } 48 49 void TearDown() override 50 { 51 TestHelper::DestroyEcmaVMWithScope(instance, scope); 52 } 53 54 EcmaVM *instance {nullptr}; 55 EcmaHandleScope *scope {nullptr}; 56 JSThread *thread {nullptr}; 57protected: 58 std::shared_ptr<JSPandaFile> CreateJSPandaFile(const char *source, const CString filename) 59 { 60 Parser parser; 61 const std::string fn = "SRC.pa"; // test file name : "SRC.pa" 62 auto res = parser.Parse(source, fn); 63 EXPECT_EQ(parser.ShowError().err, Error::ErrorType::ERR_NONE); 64 65 std::unique_ptr<const File> pfPtr = pandasm::AsmEmitter::Emit(res.Value()); 66 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance(); 67 std::shared_ptr<JSPandaFile> pf = pfManager->NewJSPandaFile(pfPtr.release(), filename); 68 return pf; 69 } 70}; 71 72HWTEST_F_L0(JSPandaFileTest, CreateJSPandaFile) 73{ 74 const char *source = R"( 75 .function void foo() {} 76 )"; 77 const CString fileName = "test.pa"; 78 std::shared_ptr<JSPandaFile> pf = CreateJSPandaFile(source, fileName); 79 EXPECT_TRUE(pf != nullptr); 80} 81 82HWTEST_F_L0(JSPandaFileTest, GetJSPandaFileDesc) 83{ 84 const char *source = R"( 85 .function void foo() {} 86 )"; 87 const CString fileName = "test.pa"; 88 std::shared_ptr<JSPandaFile> pf = CreateJSPandaFile(source, fileName); 89 const CString expectFileName = pf->GetJSPandaFileDesc(); 90 EXPECT_STREQ(expectFileName.c_str(), "test.pa"); 91} 92 93HWTEST_F_L0(JSPandaFileTest, GetPandaFile) 94{ 95 const char *source = R"( 96 .function void foo() {} 97 )"; 98 const CString fileName = "test.pa"; 99 std::shared_ptr<JSPandaFile> pf = CreateJSPandaFile(source, fileName); 100 const File *file = pf->GetPandaFile(); 101 EXPECT_TRUE(file != nullptr); 102} 103 104HWTEST_F_L0(JSPandaFileTest, GetMethodLiterals_GetNumMethods) 105{ 106 const char *source = R"( 107 .function void foo1() {} 108 .function void foo2() {} 109 .function void foo3() {} 110 )"; 111 const CString fileName = "test.pa"; 112 std::shared_ptr<JSPandaFile> pf = CreateJSPandaFile(source, fileName); 113 MethodLiteral *method = pf->GetMethodLiterals(); 114 EXPECT_TRUE(method != nullptr); 115 116 uint32_t methodNum = pf->GetNumMethods(); 117 EXPECT_EQ(methodNum, 3U); // 3 : number of methods 118} 119 120HWTEST_F_L0(JSPandaFileTest, SetMethodLiteralToMap_FindMethodLiteral) 121{ 122 const char *source = R"( 123 .function void foo1() {} 124 .function void foo2() {} 125 .function void foo3() {} 126 )"; 127 const CString fileName = "test.pa"; 128 std::shared_ptr<JSPandaFile> pf = CreateJSPandaFile(source, fileName); 129 const File *file = pf->GetPandaFile(); 130 const uint8_t *typeDesc = utf::CStringAsMutf8("L_GLOBAL;"); 131 File::EntityId classId = file->GetClassId(typeDesc); 132 EXPECT_TRUE(classId.IsValid()); 133 134 ClassDataAccessor cda(*file, classId); 135 std::vector<File::EntityId> methodId {}; 136 int count = 0; 137 cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) { 138 methodId.push_back(mda.GetMethodId()); 139 count++; 140 }); 141 EXPECT_EQ(count, 3); // 3 : number of methods 142 143 MethodLiteral *method1 = new MethodLiteral(methodId[0]); 144 MethodLiteral *method2 = new MethodLiteral(methodId[1]); 145 MethodLiteral *method3 = new MethodLiteral(methodId[2]); 146 pf->SetMethodLiteralToMap(method1); 147 pf->SetMethodLiteralToMap(method2); 148 pf->SetMethodLiteralToMap(method3); 149 EXPECT_STREQ(MethodLiteral::ParseFunctionName(pf.get(), methodId[0]).c_str(), "foo1"); 150 EXPECT_STREQ(MethodLiteral::ParseFunctionName(pf.get(), methodId[1]).c_str(), "foo2"); 151 EXPECT_STREQ(MethodLiteral::ParseFunctionName(pf.get(), methodId[2]).c_str(), "foo3"); 152} 153 154HWTEST_F_L0(JSPandaFileTest, GetOrInsertConstantPool_GetConstpoolIndex_GetConstpoolMap) 155{ 156 const char *source = R"( 157 .function void foo1() {} 158 .function void foo2() {} 159 .function void foo3() {} 160 )"; 161 const CString fileName = "test.pa"; 162 std::shared_ptr<JSPandaFile> pf = CreateJSPandaFile(source, fileName); 163 const File *file = pf->GetPandaFile(); 164 const uint8_t *typeDesc = utf::CStringAsMutf8("L_GLOBAL;"); 165 File::EntityId classId = file->GetClassId(typeDesc); 166 EXPECT_TRUE(classId.IsValid()); 167 168 ClassDataAccessor cda(*file, classId); 169 std::vector<File::EntityId> methodId {}; 170 int count = 0; 171 cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) { 172 methodId.push_back(mda.GetMethodId()); 173 count++; 174 }); 175 EXPECT_EQ(count, 3); // 3 : number of methods 176 177 uint32_t index1 = pf->GetOrInsertConstantPool(ConstPoolType::METHOD, methodId[0].GetOffset()); 178 uint32_t index2 = pf->GetOrInsertConstantPool(ConstPoolType::METHOD, methodId[1].GetOffset()); 179 uint32_t index3 = pf->GetOrInsertConstantPool(ConstPoolType::METHOD, methodId[2].GetOffset()); 180 EXPECT_EQ(index1, 0U); 181 EXPECT_EQ(index2, 1U); 182 EXPECT_EQ(index3, 2U); 183 184 uint32_t conPoolIndex = pf->GetConstpoolIndex(); 185 EXPECT_EQ(conPoolIndex, 3U); 186 187 CUnorderedMap<uint32_t, uint64_t> constpoolMap = pf->GetConstpoolMap(); 188 ConstPoolValue constPoolValue1(constpoolMap.at(methodId[0].GetOffset())); 189 ConstPoolValue constPoolValue2(constpoolMap.at(methodId[1].GetOffset())); 190 ConstPoolValue constPoolValue3(constpoolMap.at(methodId[2].GetOffset())); 191 ConstPoolType type1 = constPoolValue1.GetConstpoolType(); 192 ConstPoolType type2 = constPoolValue2.GetConstpoolType(); 193 ConstPoolType type3 = constPoolValue3.GetConstpoolType(); 194 uint32_t gotIndex1 = constPoolValue1.GetConstpoolIndex(); 195 uint32_t gotIndex2 = constPoolValue2.GetConstpoolIndex(); 196 uint32_t gotIndex3 = constPoolValue3.GetConstpoolIndex(); 197 EXPECT_EQ(type1, ConstPoolType::METHOD); 198 EXPECT_EQ(type2, ConstPoolType::METHOD); 199 EXPECT_EQ(type3, ConstPoolType::METHOD); 200 EXPECT_EQ(gotIndex1, 0U); 201 EXPECT_EQ(gotIndex2, 1U); 202 EXPECT_EQ(gotIndex3, 2U); 203} 204 205HWTEST_F_L0(JSPandaFileTest, GetMainMethodIndex_UpdateMainMethodIndex) 206{ 207 const char *source = R"( 208 .function void func1() {} 209 .function void func2() {} 210 )"; 211 const CString fileName = "test.pa"; 212 std::shared_ptr<JSPandaFile> pf = CreateJSPandaFile(source, fileName); 213 const File *file = pf->GetPandaFile(); 214 const uint8_t *typeDesc = utf::CStringAsMutf8("L_GLOBAL;"); 215 File::EntityId classId = file->GetClassId(typeDesc); 216 EXPECT_TRUE(classId.IsValid()); 217 218 ClassDataAccessor cda(*file, classId); 219 std::vector<File::EntityId> methodId {}; 220 int count = 0; 221 cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) { 222 methodId.push_back(mda.GetMethodId()); 223 count++; 224 }); 225 EXPECT_EQ(count, 2); // 2 : number of methods 226 227 uint32_t mainMethodIndex = pf->GetMainMethodIndex(); 228 EXPECT_EQ(mainMethodIndex, 0U); 229 230 pf->UpdateMainMethodIndex(methodId[0].GetOffset()); 231 mainMethodIndex = pf->GetMainMethodIndex(); 232 EXPECT_EQ(mainMethodIndex, methodId[0].GetOffset()); 233 234 pf->UpdateMainMethodIndex(methodId[1].GetOffset()); 235 mainMethodIndex = pf->GetMainMethodIndex(); 236 EXPECT_EQ(mainMethodIndex, methodId[1].GetOffset()); 237} 238 239HWTEST_F_L0(JSPandaFileTest, GetClasses) 240{ 241 const char *source = R"( 242 .function void foo() {} 243 )"; 244 const CString fileName = "test.pa"; 245 std::shared_ptr<JSPandaFile> pf = CreateJSPandaFile(source, fileName); 246 const File *file = pf->GetPandaFile(); 247 const uint8_t *typeDesc = utf::CStringAsMutf8("L_GLOBAL;"); 248 File::EntityId classId = file->GetClassId(typeDesc); 249 EXPECT_TRUE(classId.IsValid()); 250 251 const File::Header *header = file->GetHeader(); 252 Span fileData(file->GetBase(), header->file_size); 253 Span classIdxData = fileData.SubSpan(header->class_idx_off, header->num_classes * sizeof(uint32_t)); 254 auto classesData = Span(reinterpret_cast<const uint32_t *>(classIdxData.data()), header->num_classes); 255 256 Span<const uint32_t> classes = pf->GetClasses(); 257 EXPECT_EQ(classes.Data(), classesData.Data()); 258} 259 260HWTEST_F_L0(JSPandaFileTest, IsModule_IsCjs) 261{ 262 const char *source1 = R"( 263 .function void foo1() {} 264 )"; 265 const CString fileName1 = "test1.pa"; 266 std::shared_ptr<JSPandaFile> pf1 = CreateJSPandaFile(source1, fileName1); 267 JSPandaFile::JSRecordInfo info = 268 const_cast<JSPandaFile *>(pf1.get())-> FindRecordInfo(JSPandaFile::ENTRY_FUNCTION_NAME); 269 EXPECT_EQ(pf1->IsModule(&info), false); 270 EXPECT_EQ(pf1->IsCjs(&info), false); 271} 272 273HWTEST_F_L0(JSPandaFileTest, SetLoadedAOTStatus_IsLoadedAOT) 274{ 275 const char *source = R"( 276 .function void foo() {} 277 )"; 278 const CString fileName = "test.pa"; 279 std::shared_ptr<JSPandaFile> pf = CreateJSPandaFile(source, fileName); 280 bool isLoadedAOT = pf->IsLoadedAOT(); 281 EXPECT_EQ(isLoadedAOT, false); 282 283 pf->SetAOTFileInfoIndex(0); 284 isLoadedAOT = pf->IsLoadedAOT(); 285 EXPECT_EQ(isLoadedAOT, true); 286} 287 288HWTEST_F_L0(JSPandaFileTest, GetFileUniqId) 289{ 290 const char *source = R"( 291 .function void foo() {} 292 )"; 293 const CString fileName = "test.pa"; 294 std::shared_ptr<JSPandaFile> pf = CreateJSPandaFile(source, fileName); 295 EXPECT_EQ(pf->GetFileUniqId(), merge_hashes(panda_file::File::CalcFilenameHash(""), 296 GetHash32(reinterpret_cast<const uint8_t *>(pf->GetPandaFile()->GetHeader()), 297 sizeof(panda_file::File::Header)))); 298} 299 300HWTEST_F_L0(JSPandaFileTest, IsParsedConstpoolOfCurrentVM) 301{ 302 const char *source = R"( 303 .function void foo() {} 304 )"; 305 const CString fileName = "test.pa"; 306 std::shared_ptr<JSPandaFile> pf = CreateJSPandaFile(source, fileName); 307 auto &recordInfo = pf->FindRecordInfo(JSPandaFile::ENTRY_FUNCTION_NAME); 308 EXPECT_TRUE(!recordInfo.IsParsedConstpoolOfCurrentVM(instance)); 309 recordInfo.SetParsedConstpoolVM(instance); 310 EXPECT_TRUE(pf->FindRecordInfo(JSPandaFile::ENTRY_FUNCTION_NAME).IsParsedConstpoolOfCurrentVM(instance)); 311} 312 313HWTEST_F_L0(JSPandaFileTest, NormalizedFileDescTest) 314{ 315 const char *source = R"( 316 .function void foo() {} 317 )"; 318 CString fileName = "/data/storage/el1/bundle/entry/ets/modules.abc"; 319 std::shared_ptr<JSPandaFile> pf = CreateJSPandaFile(source, fileName); 320 EXPECT_EQ(pf->GetNormalizedFileDesc(), "entry/ets/modules.abc"); 321 322 fileName = "/data/storage/el1/bundle/entry/ets/widgets.abc"; 323 pf = CreateJSPandaFile(source, fileName); 324 EXPECT_EQ(pf->GetNormalizedFileDesc(), "entry/ets/widgets.abc"); 325 326 fileName = "/data/app/el1/bundle/public/com.xx.xx/entry.hsp/entry/ets/modules.abc"; 327 pf = CreateJSPandaFile(source, fileName); 328 EXPECT_EQ(pf->GetNormalizedFileDesc(), "entry/ets/modules.abc"); 329 330 fileName = "/data/app/el1/bundle/public/com.xx.xx/entry.hap/entry/ets/widgets.abc"; 331 pf = CreateJSPandaFile(source, fileName); 332 EXPECT_EQ(pf->GetNormalizedFileDesc(), "entry/ets/widgets.abc"); 333 334 fileName = "/system/app/Camera/Camera.hap/entry1/ets/modules.abc"; 335 pf = CreateJSPandaFile(source, fileName); 336 EXPECT_EQ(pf->GetNormalizedFileDesc(), "entry1/ets/modules.abc"); 337 338 fileName = "test.pa"; 339 pf = CreateJSPandaFile(source, fileName); 340 EXPECT_EQ(pf->GetNormalizedFileDesc(), fileName); 341 342 fileName = "libapp.ability.AbilityStage.z.so/app.ability.AbilityStage.js"; 343 pf = CreateJSPandaFile(source, fileName); 344 EXPECT_EQ(pf->GetNormalizedFileDesc(), fileName); 345} 346} // namespace panda::test