• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 ark::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 
GetClassHashTableABC1(const std::string & fn)125 void GetClassHashTableABC1(const std::string &fn)
126 {
127     auto source = R"(
128             .record Animal {}
129             .function i32 Animal.fun() <static> {
130                 ldai 1
131                 return
132             }
133         )";
134 
135     pandasm::Parser parser;
136     auto res = parser.Parse(source);
137     ASSERT_TRUE(res);
138     ASSERT_TRUE(pandasm::AsmEmitter::Emit(fn, res.Value()));
139 }
140 
GetClassHashTableABC2(const std::string & fn)141 void GetClassHashTableABC2(const std::string &fn)
142 {
143     auto source = R"(
144             .record Animal <external>
145             .record Cat {}
146             .record Dog {}
147             .record Pig {}
148             .function i32 Animal.fun() <external, static>
149             .function i32 Cat.main() <static> {
150                 call.short Animal.fun
151                 return
152             }
153         )";
154 
155     pandasm::Parser parser;
156     auto res = parser.Parse(source);
157     ASSERT_TRUE(res);
158     ASSERT_TRUE(pandasm::AsmEmitter::Emit(fn, res.Value()));
159 }
160 
GetClassHashTableAN(const std::string & fn1,const std::string & fn2,const std::string & fnAot,const std::string & fnPaoc,const std::string & stdlib)161 void GetClassHashTableAN(const std::string &fn1, const std::string &fn2, const std::string &fnAot,
162                          const std::string &fnPaoc, const std::string &stdlib)
163 {
164     auto res = os::exec::Exec(fnPaoc.c_str(), "--paoc-panda-files", fn2.c_str(), "--panda-files", fn1.c_str(),
165                               "--paoc-output", fnAot.c_str(), "--boot-panda-files", stdlib.c_str());
166     ASSERT_TRUE(res);
167     ASSERT_EQ(res.Value(), 0U);
168 }
169 
TEST_F(ClassHashTableTest,GetClassHashTable)170 TEST_F(ClassHashTableTest, GetClassHashTable)
171 {
172     if (RUNTIME_ARCH != Arch::X86_64) {
173         GTEST_SKIP();
174     }
175 
176     TmpFile aotFname("TestTwo.an");
177     TmpFile pandaFname1("Animal.abc");
178     TmpFile pandaFname2("Cat.abc");
179 
180     GetClassHashTableABC1(pandaFname1.GetFileName());
181     GetClassHashTableABC2(pandaFname2.GetFileName());
182     GetClassHashTableAN(pandaFname1.GetFileName(), pandaFname2.GetFileName(), aotFname.GetFileName(), GetPaocFile(),
183                         GetPandaStdLibFile());
184 
185     std::string filename = os::GetAbsolutePath(aotFname.GetFileName());
186     auto aotFileRet = AotFile::Open(filename, 0U, true);
187     ASSERT(aotFileRet.Value() != nullptr);
188     auto aotFile = std::move(aotFileRet.Value());
189 
190     for (size_t i = 0; i < aotFile->GetFilesCount(); i++) {
191         auto fileHeader = aotFile->FileHeaders()[i];
192         auto table = aotFile->GetClassHashTable(fileHeader);
193 
194         ASSERT(!table.empty());
195         ASSERT_EQ(table.size(), fileHeader.classHashTableSize);
196     }
197 
198     for (size_t i = 0; i < aotFile->GetFilesCount(); i++) {
199         auto fileHeader = aotFile->FileHeaders()[i];
200         AotPandaFile aotPandaFile(aotFile.get(), &fileHeader);
201         auto table = aotPandaFile.GetClassHashTable();
202 
203         ASSERT(!table.empty());
204         ASSERT_EQ(table.size(), fileHeader.classHashTableSize);
205     }
206 }
207 
TEST_F(ClassHashTableTest,DumpClassHashTable)208 TEST_F(ClassHashTableTest, DumpClassHashTable)
209 {
210     if (RUNTIME_ARCH != Arch::X86_64) {
211         GTEST_SKIP();
212     }
213 
214     TmpFile pandaFname("DumpClassHashTableTest.abc");
215     TmpFile aotFname("DumpClassHashTableTest.an");
216 
217     {
218         pandasm::Parser parser;
219         auto res = parser.Parse(GetSourceCode());
220         ASSERT_TRUE(res);
221         ASSERT_TRUE(pandasm::AsmEmitter::Emit(pandaFname.GetFileName(), res.Value()));
222     }
223 
224     {
225         auto res = os::exec::Exec(GetPaocFile(), "--paoc-panda-files", pandaFname.GetFileName(), "--paoc-output",
226                                   aotFname.GetFileName(), "--boot-panda-files", GetPandaStdLibFile());
227         ASSERT_TRUE(res);
228         ASSERT_EQ(res.Value(), 0U);
229     }
230 
231     {
232         std::string filename = os::GetAbsolutePath(aotFname.GetFileName());
233         auto res = os::exec::Exec(GetAotdumpFile(), "--show-code=disasm", filename.c_str());
234         ASSERT_TRUE(res);
235         ASSERT_EQ(res.Value(), 0U);
236     }
237 }
238 
TEST_F(ClassHashTableTest,LoadClassHashTableFromAnFileToAbcFile)239 TEST_F(ClassHashTableTest, LoadClassHashTableFromAnFileToAbcFile)
240 {
241     if (RUNTIME_ARCH != Arch::X86_64) {
242         GTEST_SKIP();
243     }
244 
245     TmpFile pandaFname("LoadClassHashTableFromAnFileToAbcFileTest.abc");
246     TmpFile aotFname("LoadClassHashTableFromAnFileToAbcFileTest.an");
247 
248     {
249         pandasm::Parser parser;
250         auto res = parser.Parse(GetSourceCode());
251         ASSERT_TRUE(res);
252         ASSERT_TRUE(pandasm::AsmEmitter::Emit(pandaFname.GetFileName(), res.Value()));
253     }
254 
255     auto pfile = panda_file::OpenPandaFile(pandaFname.GetFileName());
256 
257     {
258         auto res = os::exec::Exec(GetPaocFile(), "--paoc-panda-files", pandaFname.GetFileName(), "--paoc-output",
259                                   aotFname.GetFileName(), "--boot-panda-files", GetPandaStdLibFile());
260         ASSERT_TRUE(res);
261         ASSERT_EQ(res.Value(), 0U);
262     }
263 
264     std::string filename = os::GetAbsolutePath(aotFname.GetFileName());
265     auto aotFileRet = AotFile::Open(filename, 0U, true);
266     ASSERT(aotFileRet.Value() != nullptr);
267     auto aotFile = std::move(aotFileRet.Value());
268 
269     auto fileHeader = aotFile->FileHeaders()[0U];
270     AotPandaFile aotPandaFile(aotFile.get(), &fileHeader);
271     pfile->SetClassHashTable(aotPandaFile.GetClassHashTable());
272 
273     ASSERT(!pfile->GetClassHashTable().empty());
274     ASSERT_EQ(pfile->GetClassHashTable().size(), aotPandaFile.GetClassHashTable().size());
275 }
276 
TEST_F(ClassHashTableTest,LoadAbcFileCanLoadClassHashTable)277 TEST_F(ClassHashTableTest, LoadAbcFileCanLoadClassHashTable)
278 {
279     if (RUNTIME_ARCH != Arch::X86_64) {
280         GTEST_SKIP();
281     }
282 
283     TmpFile pandaFname("LoadAbcFileTest.abc");
284     TmpFile aotFname("LoadAbcFileTest.an");
285 
286     {
287         pandasm::Parser parser;
288         auto res = parser.Parse(GetSourceCode());
289         ASSERT_TRUE(res);
290         ASSERT_TRUE(pandasm::AsmEmitter::Emit(pandaFname.GetFileName(), res.Value()));
291     }
292 
293     auto pfile = panda_file::OpenPandaFile(pandaFname.GetFileName());
294 
295     {
296         auto res = os::exec::Exec(GetPaocFile(), "--gc-type=epsilon", "--paoc-panda-files", pandaFname.GetFileName(),
297                                   "--paoc-output", aotFname.GetFileName(), "--boot-panda-files", GetPandaStdLibFile());
298         ASSERT_TRUE(res);
299         ASSERT_EQ(res.Value(), 0U);
300     }
301 
302     std::string filename = os::GetAbsolutePath(pandaFname.GetFileName());
303     auto res = FileManager::LoadAbcFile(filename, panda_file::File::READ_ONLY);
304     ASSERT_TRUE(res);
305 
306     const panda_file::File *pfPtr = nullptr;
307     auto checkFilename = [&pfPtr, filename](const panda_file::File &pf) {
308         if (pf.GetFilename() == filename) {
309             pfPtr = &pf;
310             return false;
311         }
312         return true;
313     };
314     Runtime::GetCurrent()->GetClassLinker()->EnumeratePandaFiles(checkFilename);
315 
316     ASSERT(!pfPtr->GetClassHashTable().empty());
317 }
318 
GetClassIdFromClassHashTableABC(const std::string & source,const std::string & fnOut)319 void GetClassIdFromClassHashTableABC(const std::string &source, const std::string &fnOut)
320 {
321     pandasm::Parser parser;
322     auto res = parser.Parse(source);
323     ASSERT_TRUE(res);
324     ASSERT_TRUE(pandasm::AsmEmitter::Emit(fnOut, res.Value()));
325 }
326 
GetClassIdFromClassHashTableAN(const std::string & fn,const std::string & fnAot,const std::string & fnPaoc,const std::string & stdlib)327 void GetClassIdFromClassHashTableAN(const std::string &fn, const std::string &fnAot, const std::string &fnPaoc,
328                                     const std::string &stdlib)
329 {
330     auto res = os::exec::Exec(fnPaoc.c_str(), "--gc-type=epsilon", "--paoc-panda-files", fn.c_str(), "--paoc-output",
331                               fnAot.c_str(), "--boot-panda-files", stdlib.c_str());
332     ASSERT_TRUE(res);
333     ASSERT_EQ(res.Value(), 0U);
334 }
335 
TEST_F(ClassHashTableTest,GetClassIdFromClassHashTable)336 TEST_F(ClassHashTableTest, GetClassIdFromClassHashTable)
337 {
338     if (RUNTIME_ARCH != Arch::X86_64) {
339         GTEST_SKIP();
340     }
341 
342     TmpFile pandaFname("GetClassIdFromClassHashTableTest.abc");
343     TmpFile aotFname("GetClassIdFromClassHashTableTest.an");
344 
345     GetClassIdFromClassHashTableABC(GetSourceCode(), pandaFname.GetFileName());
346 
347     auto pfile = panda_file::OpenPandaFile(pandaFname.GetFileName());
348 
349     auto *descriptorA = reinterpret_cast<const uint8_t *>("A");
350     auto *descriptorB = reinterpret_cast<const uint8_t *>("B");
351     auto *descriptorC = reinterpret_cast<const uint8_t *>("C");
352     auto *descriptorD = reinterpret_cast<const uint8_t *>("D");
353     auto *descriptorE = reinterpret_cast<const uint8_t *>("E");
354 
355     auto classId1A = pfile->GetClassId(descriptorA);
356     auto classId1B = pfile->GetClassId(descriptorB);
357     auto classId1C = pfile->GetClassId(descriptorC);
358     auto classId1D = pfile->GetClassId(descriptorD);
359     auto classId1E = pfile->GetClassId(descriptorE);
360 
361     GetClassIdFromClassHashTableAN(pandaFname.GetFileName(), aotFname.GetFileName(), GetPaocFile(),
362                                    GetPandaStdLibFile());
363 
364     std::string filename = os::GetAbsolutePath(pandaFname.GetFileName());
365     auto res = FileManager::LoadAbcFile(filename, panda_file::File::READ_ONLY);
366     ASSERT_TRUE(res);
367 
368     const panda_file::File *pfPtr = nullptr;
369     Runtime::GetCurrent()->GetClassLinker()->EnumeratePandaFiles([&pfPtr, filename](const panda_file::File &pf) {
370         if (pf.GetFilename() == filename) {
371             pfPtr = &pf;
372             return false;
373         }
374         return true;
375     });
376 
377     auto classId2A = pfPtr->GetClassIdFromClassHashTable(descriptorA);
378     auto classId2B = pfPtr->GetClassIdFromClassHashTable(descriptorB);
379     auto classId2C = pfPtr->GetClassIdFromClassHashTable(descriptorC);
380     auto classId2D = pfPtr->GetClassIdFromClassHashTable(descriptorD);
381     auto classId2E = pfPtr->GetClassIdFromClassHashTable(descriptorE);
382 
383     ASSERT_EQ(classId1A, classId2A);
384     ASSERT_EQ(classId1B, classId2B);
385     ASSERT_EQ(classId1C, classId2C);
386     ASSERT_EQ(classId1D, classId2D);
387     ASSERT_EQ(classId1E, classId2E);
388 }
389 
390 }  // namespace ark::compiler
391