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