• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 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 "aot/aot_builder/aot_builder.h"
17 #include "aot/aot_manager.h"
18 #include "assembly-parser.h"
19 #include "unit_test.h"
20 #include "os/exec.h"
21 #include "os/filesystem.h"
22 #include "runtime/include/file_manager.h"
23 
24 namespace panda::compiler {
25 class ClassHashTableTest : public AsmTest {
26 public:
ClassHashTableTest()27     ClassHashTableTest()
28     {
29         std::string exePath = GetExecPath();
30         auto pos = exePath.rfind('/');
31         paocPath_ = exePath.substr(0U, pos) + "/../bin/ark_aot";
32         aotdumpPath_ = exePath.substr(0U, pos) + "/../bin/ark_aotdump";
33         pandastdlibPath_ = GetPaocDirectory() + "/../pandastdlib/arkstdlib.abc";
34     }
35 
GetPaocFile() const36     const char *GetPaocFile() const
37     {
38         return paocPath_.c_str();
39     }
40 
GetAotdumpFile() const41     const char *GetAotdumpFile() const
42     {
43         return aotdumpPath_.c_str();
44     }
45 
GetPandaStdLibFile() const46     const char *GetPandaStdLibFile() const
47     {
48         return pandastdlibPath_.c_str();
49     }
50 
GetPaocDirectory() const51     std::string GetPaocDirectory() const
52     {
53         auto pos = paocPath_.rfind('/');
54         return paocPath_.substr(0U, pos);
55     }
56 
GetSourceCode() const57     std::string GetSourceCode() const
58     {
59         return source_;
60     }
61 
62 private:
63     std::string paocPath_;
64     std::string aotdumpPath_;
65     std::string pandastdlibPath_;
66     const std::string source_ = R"(
67         .record A {}
68         .record B {}
69         .record C {}
70         .record D {}
71         .record E {}
72 
73         .function i32 A.f() {
74             ldai 1
75             return
76         }
77 
78         .function i32 B.f() {
79             ldai 2
80             return
81         }
82 
83         .function i32 C.f() {
84             ldai 3
85             return
86         }
87 
88         .function i32 D.f() {
89             ldai 4
90             return
91         }
92 
93         .function i32 main() {
94             ldai 0
95             return
96         }
97     )";
98 };
99 
TEST_F(ClassHashTableTest,AddClassHashTable)100 TEST_F(ClassHashTableTest, AddClassHashTable)
101 {
102     TmpFile pandaFname("AddClassHashTableTest.abc");
103 
104     {
105         pandasm::Parser parser;
106         auto res = parser.Parse(GetSourceCode());
107         ASSERT_TRUE(res);
108         ASSERT_TRUE(pandasm::AsmEmitter::Emit(pandaFname.GetFileName(), res.Value()));
109     }
110 
111     auto pandaFilePtr = panda_file::OpenPandaFile(pandaFname.GetFileName());
112     ASSERT(pandaFilePtr != nullptr);
113     auto &pfileRef = *pandaFilePtr;
114 
115     AotBuilder aotBuilder;
116     aotBuilder.AddClassHashTable(pfileRef);
117 
118     auto entityPairHeaders = aotBuilder.GetEntityPairHeaders();
119     auto classHashTablesSize = aotBuilder.GetClassHashTableSize()->back();
120 
121     ASSERT(!entityPairHeaders->empty());
122     ASSERT_EQ(classHashTablesSize, entityPairHeaders->size());
123 }
124 
TEST_F(ClassHashTableTest,GetClassHashTable)125 TEST_F(ClassHashTableTest, GetClassHashTable)
126 {
127     if (RUNTIME_ARCH != Arch::X86_64) {
128         GTEST_SKIP();
129     }
130 
131     TmpFile aotFname("TestTwo.an");
132     TmpFile pandaFname1("Animal.abc");
133     TmpFile pandaFname2("Cat.abc");
134 
135     {
136         auto source = R"(
137             .record Animal {}
138             .function i32 Animal.fun() <static> {
139                 ldai 1
140                 return
141             }
142         )";
143 
144         pandasm::Parser parser;
145         auto res = parser.Parse(source);
146         ASSERT_TRUE(res);
147         ASSERT_TRUE(pandasm::AsmEmitter::Emit(pandaFname1.GetFileName(), res.Value()));
148     }
149 
150     {
151         auto source = R"(
152             .record Animal <external>
153             .record Cat {}
154             .record Dog {}
155             .record Pig {}
156             .function i32 Animal.fun() <external, static>
157             .function i32 Cat.main() <static> {
158                 call.short Animal.fun
159                 return
160             }
161         )";
162 
163         pandasm::Parser parser;
164         auto res = parser.Parse(source);
165         ASSERT_TRUE(res);
166         ASSERT_TRUE(pandasm::AsmEmitter::Emit(pandaFname2.GetFileName(), res.Value()));
167     }
168 
169     {
170         auto res = os::exec::Exec(GetPaocFile(), "--paoc-panda-files", pandaFname2.GetFileName(), "--panda-files",
171                                   pandaFname1.GetFileName(), "--paoc-output", aotFname.GetFileName(),
172                                   "--boot-panda-files", GetPandaStdLibFile());
173         ASSERT_TRUE(res);
174         ASSERT_EQ(res.Value(), 0U);
175     }
176 
177     std::string filename = os::GetAbsolutePath(aotFname.GetFileName());
178     auto aotFileRet = AotFile::Open(filename, 0U, true);
179     ASSERT(aotFileRet.Value() != nullptr);
180     auto aotFile = std::move(aotFileRet.Value());
181 
182     for (size_t i = 0; i < aotFile->GetFilesCount(); i++) {
183         auto fileHeader = aotFile->FileHeaders()[i];
184         auto table = aotFile->GetClassHashTable(fileHeader);
185 
186         ASSERT(!table.empty());
187         ASSERT_EQ(table.size(), fileHeader.classHashTableSize);
188     }
189 
190     for (size_t i = 0; i < aotFile->GetFilesCount(); i++) {
191         auto fileHeader = aotFile->FileHeaders()[i];
192         AotPandaFile aotPandaFile(aotFile.get(), &fileHeader);
193         auto table = aotPandaFile.GetClassHashTable();
194 
195         ASSERT(!table.empty());
196         ASSERT_EQ(table.size(), fileHeader.classHashTableSize);
197     }
198 }
199 
TEST_F(ClassHashTableTest,DumpClassHashTable)200 TEST_F(ClassHashTableTest, DumpClassHashTable)
201 {
202     if (RUNTIME_ARCH != Arch::X86_64) {
203         GTEST_SKIP();
204     }
205 
206     TmpFile pandaFname("DumpClassHashTableTest.abc");
207     TmpFile aotFname("DumpClassHashTableTest.an");
208 
209     {
210         pandasm::Parser parser;
211         auto res = parser.Parse(GetSourceCode());
212         ASSERT_TRUE(res);
213         ASSERT_TRUE(pandasm::AsmEmitter::Emit(pandaFname.GetFileName(), res.Value()));
214     }
215 
216     {
217         auto res = os::exec::Exec(GetPaocFile(), "--paoc-panda-files", pandaFname.GetFileName(), "--paoc-output",
218                                   aotFname.GetFileName(), "--boot-panda-files", GetPandaStdLibFile());
219         ASSERT_TRUE(res);
220         ASSERT_EQ(res.Value(), 0U);
221     }
222 
223     {
224         std::string filename = os::GetAbsolutePath(aotFname.GetFileName());
225         auto res = os::exec::Exec(GetAotdumpFile(), "--show-code=disasm", filename.c_str());
226         ASSERT_TRUE(res);
227         ASSERT_EQ(res.Value(), 0U);
228     }
229 }
230 
TEST_F(ClassHashTableTest,LoadClassHashTableFromAnFileToAbcFile)231 TEST_F(ClassHashTableTest, LoadClassHashTableFromAnFileToAbcFile)
232 {
233     if (RUNTIME_ARCH != Arch::X86_64) {
234         GTEST_SKIP();
235     }
236 
237     TmpFile pandaFname("LoadClassHashTableFromAnFileToAbcFileTest.abc");
238     TmpFile aotFname("LoadClassHashTableFromAnFileToAbcFileTest.an");
239 
240     {
241         pandasm::Parser parser;
242         auto res = parser.Parse(GetSourceCode());
243         ASSERT_TRUE(res);
244         ASSERT_TRUE(pandasm::AsmEmitter::Emit(pandaFname.GetFileName(), res.Value()));
245     }
246 
247     auto pfile = panda_file::OpenPandaFile(pandaFname.GetFileName());
248 
249     {
250         auto res = os::exec::Exec(GetPaocFile(), "--paoc-panda-files", pandaFname.GetFileName(), "--paoc-output",
251                                   aotFname.GetFileName(), "--boot-panda-files", GetPandaStdLibFile());
252         ASSERT_TRUE(res);
253         ASSERT_EQ(res.Value(), 0U);
254     }
255 
256     std::string filename = os::GetAbsolutePath(aotFname.GetFileName());
257     auto aotFileRet = AotFile::Open(filename, 0U, true);
258     ASSERT(aotFileRet.Value() != nullptr);
259     auto aotFile = std::move(aotFileRet.Value());
260 
261     auto fileHeader = aotFile->FileHeaders()[0U];
262     AotPandaFile aotPandaFile(aotFile.get(), &fileHeader);
263     pfile->SetClassHashTable(aotPandaFile.GetClassHashTable());
264 
265     ASSERT(!pfile->GetClassHashTable().empty());
266     ASSERT_EQ(pfile->GetClassHashTable().size(), aotPandaFile.GetClassHashTable().size());
267 }
268 
TEST_F(ClassHashTableTest,LoadAbcFileCanLoadClassHashTable)269 TEST_F(ClassHashTableTest, LoadAbcFileCanLoadClassHashTable)
270 {
271     if (RUNTIME_ARCH != Arch::X86_64) {
272         GTEST_SKIP();
273     }
274 
275     TmpFile pandaFname("LoadAbcFileTest.abc");
276     TmpFile aotFname("LoadAbcFileTest.an");
277 
278     {
279         pandasm::Parser parser;
280         auto res = parser.Parse(GetSourceCode());
281         ASSERT_TRUE(res);
282         ASSERT_TRUE(pandasm::AsmEmitter::Emit(pandaFname.GetFileName(), res.Value()));
283     }
284 
285     auto pfile = panda_file::OpenPandaFile(pandaFname.GetFileName());
286 
287     {
288         auto res = os::exec::Exec(GetPaocFile(), "--gc-type=epsilon", "--paoc-panda-files", pandaFname.GetFileName(),
289                                   "--paoc-output", aotFname.GetFileName(), "--boot-panda-files", GetPandaStdLibFile());
290         ASSERT_TRUE(res);
291         ASSERT_EQ(res.Value(), 0U);
292     }
293 
294     std::string filename = os::GetAbsolutePath(pandaFname.GetFileName());
295     auto res = FileManager::LoadAbcFile(filename, panda_file::File::READ_ONLY);
296     ASSERT_TRUE(res);
297 
298     const panda_file::File *pfPtr = nullptr;
299     Runtime::GetCurrent()->GetClassLinker()->EnumeratePandaFiles([&pfPtr, filename](const panda_file::File &pf) {
300         if (pf.GetFilename() == filename) {
301             pfPtr = &pf;
302             return false;
303         }
304         return true;
305     });
306 
307     ASSERT(!pfPtr->GetClassHashTable().empty());
308 }
309 
TEST_F(ClassHashTableTest,GetClassIdFromClassHashTable)310 TEST_F(ClassHashTableTest, GetClassIdFromClassHashTable)
311 {
312     if (RUNTIME_ARCH != Arch::X86_64) {
313         GTEST_SKIP();
314     }
315 
316     TmpFile pandaFname("GetClassIdFromClassHashTableTest.abc");
317     TmpFile aotFname("GetClassIdFromClassHashTableTest.an");
318 
319     {
320         pandasm::Parser parser;
321         auto res = parser.Parse(GetSourceCode());
322         ASSERT_TRUE(res);
323         ASSERT_TRUE(pandasm::AsmEmitter::Emit(pandaFname.GetFileName(), res.Value()));
324     }
325 
326     auto pfile = panda_file::OpenPandaFile(pandaFname.GetFileName());
327 
328     auto *descriptorA = reinterpret_cast<const uint8_t *>("A");
329     auto *descriptorB = reinterpret_cast<const uint8_t *>("B");
330     auto *descriptorC = reinterpret_cast<const uint8_t *>("C");
331     auto *descriptorD = reinterpret_cast<const uint8_t *>("D");
332     auto *descriptorE = reinterpret_cast<const uint8_t *>("E");
333 
334     auto classId1A = pfile->GetClassId(descriptorA);
335     auto classId1B = pfile->GetClassId(descriptorB);
336     auto classId1C = pfile->GetClassId(descriptorC);
337     auto classId1D = pfile->GetClassId(descriptorD);
338     auto classId1E = pfile->GetClassId(descriptorE);
339 
340     {
341         auto res = os::exec::Exec(GetPaocFile(), "--gc-type=epsilon", "--paoc-panda-files", pandaFname.GetFileName(),
342                                   "--paoc-output", aotFname.GetFileName(), "--boot-panda-files", GetPandaStdLibFile());
343         ASSERT_TRUE(res);
344         ASSERT_EQ(res.Value(), 0U);
345     }
346 
347     std::string filename = os::GetAbsolutePath(pandaFname.GetFileName());
348     auto res = FileManager::LoadAbcFile(filename, panda_file::File::READ_ONLY);
349     ASSERT_TRUE(res);
350 
351     const panda_file::File *pfPtr = nullptr;
352     Runtime::GetCurrent()->GetClassLinker()->EnumeratePandaFiles([&pfPtr, filename](const panda_file::File &pf) {
353         if (pf.GetFilename() == filename) {
354             pfPtr = &pf;
355             return false;
356         }
357         return true;
358     });
359 
360     auto classId2A = pfPtr->GetClassIdFromClassHashTable(descriptorA);
361     auto classId2B = pfPtr->GetClassIdFromClassHashTable(descriptorB);
362     auto classId2C = pfPtr->GetClassIdFromClassHashTable(descriptorC);
363     auto classId2D = pfPtr->GetClassIdFromClassHashTable(descriptorD);
364     auto classId2E = pfPtr->GetClassIdFromClassHashTable(descriptorE);
365 
366     ASSERT_EQ(classId1A, classId2A);
367     ASSERT_EQ(classId1B, classId2B);
368     ASSERT_EQ(classId1C, classId2C);
369     ASSERT_EQ(classId1D, classId2D);
370     ASSERT_EQ(classId1E, classId2E);
371 }
372 
373 }  // namespace panda::compiler
374