• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 "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 exe_path = GetExecPath();
30         auto pos = exe_path.rfind('/');
31         paoc_path_ = exe_path.substr(0, pos) + "/../bin/ark_aot";
32         aotdump_path_ = exe_path.substr(0, pos) + "/../bin/ark_aotdump";
33         pandastdlib_path_ = GetPaocDirectory() + "/../pandastdlib/arkstdlib.abc";
34     }
35 
GetPaocFile() const36     const char *GetPaocFile() const
37     {
38         return paoc_path_.c_str();
39     }
40 
GetAotdumpFile() const41     const char *GetAotdumpFile() const
42     {
43         return aotdump_path_.c_str();
44     }
45 
GetPandaStdLibFile() const46     const char *GetPandaStdLibFile() const
47     {
48         return pandastdlib_path_.c_str();
49     }
50 
GetPaocDirectory() const51     std::string GetPaocDirectory() const
52     {
53         auto pos = paoc_path_.rfind('/');
54         return paoc_path_.substr(0, pos);
55     }
56 
GetSourceCode() const57     const std::string GetSourceCode() const
58     {
59         return source_;
60     }
61 
62 protected:
63     std::string paoc_path_;
64     std::string aotdump_path_;
65     std::string pandastdlib_path_;
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 panda_fname("AddClassHashTableTest.abc");
103 
104     {
105         pandasm::Parser parser;
106         auto res = parser.Parse(GetSourceCode());
107         ASSERT_TRUE(res);
108         ASSERT_TRUE(pandasm::AsmEmitter::Emit(panda_fname.GetFileName(), res.Value()));
109     }
110 
111     auto panda_file_ptr = panda_file::OpenPandaFile(panda_fname.GetFileName());
112     ASSERT(panda_file_ptr != nullptr);
113     auto &pfile_ref = *panda_file_ptr.get();
114 
115     AotBuilder aot_builder;
116     aot_builder.AddClassHashTable(pfile_ref);
117 
118     auto entity_pair_headers = aot_builder.GetEntityPairHeaders();
119     auto class_hash_tables_size = aot_builder.GetClassHashTableSize()->back();
120 
121     ASSERT(!entity_pair_headers->empty());
122     ASSERT_EQ(class_hash_tables_size, entity_pair_headers->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 aot_fname("TestTwo.an");
132     TmpFile panda_fname1("Animal.abc");
133     TmpFile panda_fname2("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(panda_fname1.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(panda_fname2.GetFileName(), res.Value()));
167     }
168 
169     {
170         auto res = os::exec::Exec(GetPaocFile(), "--paoc-panda-files", panda_fname2.GetFileName(), "--panda-files",
171                                   panda_fname1.GetFileName(), "--paoc-output", aot_fname.GetFileName(),
172                                   "--boot-panda-files", GetPandaStdLibFile());
173         ASSERT_TRUE(res);
174         ASSERT_EQ(res.Value(), 0);
175     }
176 
177     std::string filename = os::GetAbsolutePath(aot_fname.GetFileName());
178     auto aot_file_ret = AotFile::Open(filename, 0, true);
179     ASSERT(aot_file_ret.Value() != nullptr);
180     auto aot_file = std::move(aot_file_ret.Value());
181 
182     for (size_t i = 0; i < aot_file->GetFilesCount(); i++) {
183         auto file_header = aot_file->FileHeaders()[i];
184         auto table = aot_file->GetClassHashTable(file_header);
185 
186         ASSERT(!table.empty());
187         ASSERT_EQ(table.size(), file_header.class_hash_table_size);
188     }
189 
190     for (size_t i = 0; i < aot_file->GetFilesCount(); i++) {
191         auto file_header = aot_file->FileHeaders()[i];
192         AotPandaFile aot_panda_file(aot_file.get(), &file_header);
193         auto table = aot_panda_file.GetClassHashTable();
194 
195         ASSERT(!table.empty());
196         ASSERT_EQ(table.size(), file_header.class_hash_table_size);
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 panda_fname("DumpClassHashTableTest.abc");
207     TmpFile aot_fname("DumpClassHashTableTest.an");
208 
209     {
210         pandasm::Parser parser;
211         auto res = parser.Parse(GetSourceCode());
212         ASSERT_TRUE(res);
213         ASSERT_TRUE(pandasm::AsmEmitter::Emit(panda_fname.GetFileName(), res.Value()));
214     }
215 
216     {
217         auto res = os::exec::Exec(GetPaocFile(), "--paoc-panda-files", panda_fname.GetFileName(), "--paoc-output",
218                                   aot_fname.GetFileName(), "--boot-panda-files", GetPandaStdLibFile());
219         ASSERT_TRUE(res);
220         ASSERT_EQ(res.Value(), 0);
221     }
222 
223     {
224         std::string filename = os::GetAbsolutePath(aot_fname.GetFileName());
225         auto res = os::exec::Exec(GetAotdumpFile(), "--show-code=disasm", filename.c_str());
226         ASSERT_TRUE(res);
227         ASSERT_EQ(res.Value(), 0);
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 panda_fname("LoadClassHashTableFromAnFileToAbcFileTest.abc");
238     TmpFile aot_fname("LoadClassHashTableFromAnFileToAbcFileTest.an");
239 
240     {
241         pandasm::Parser parser;
242         auto res = parser.Parse(GetSourceCode());
243         ASSERT_TRUE(res);
244         ASSERT_TRUE(pandasm::AsmEmitter::Emit(panda_fname.GetFileName(), res.Value()));
245     }
246 
247     auto pfile = panda_file::OpenPandaFile(panda_fname.GetFileName());
248 
249     {
250         auto res = os::exec::Exec(GetPaocFile(), "--paoc-panda-files", panda_fname.GetFileName(), "--paoc-output",
251                                   aot_fname.GetFileName(), "--boot-panda-files", GetPandaStdLibFile());
252         ASSERT_TRUE(res);
253         ASSERT_EQ(res.Value(), 0);
254     }
255 
256     std::string filename = os::GetAbsolutePath(aot_fname.GetFileName());
257     auto aot_file_ret = AotFile::Open(filename, 0, true);
258     ASSERT(aot_file_ret.Value() != nullptr);
259     auto aot_file = std::move(aot_file_ret.Value());
260 
261     auto file_header = aot_file->FileHeaders()[0];
262     AotPandaFile aot_panda_file(aot_file.get(), &file_header);
263     pfile->SetClassHashTable(aot_panda_file.GetClassHashTable());
264 
265     ASSERT(!pfile->GetClassHashTable().empty());
266     ASSERT_EQ(pfile->GetClassHashTable().size(), aot_panda_file.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 panda_fname("LoadAbcFileTest.abc");
276     TmpFile aot_fname("LoadAbcFileTest.an");
277 
278     {
279         pandasm::Parser parser;
280         auto res = parser.Parse(GetSourceCode());
281         ASSERT_TRUE(res);
282         ASSERT_TRUE(pandasm::AsmEmitter::Emit(panda_fname.GetFileName(), res.Value()));
283     }
284 
285     auto pfile = panda_file::OpenPandaFile(panda_fname.GetFileName());
286 
287     {
288         auto res = os::exec::Exec(GetPaocFile(), "--gc-type=epsilon", "--paoc-panda-files", panda_fname.GetFileName(),
289                                   "--paoc-output", aot_fname.GetFileName(), "--boot-panda-files", GetPandaStdLibFile());
290         ASSERT_TRUE(res);
291         ASSERT_EQ(res.Value(), 0);
292     }
293 
294     std::string filename = os::GetAbsolutePath(panda_fname.GetFileName());
295     auto res = FileManager::LoadAbcFile(filename, panda_file::File::READ_ONLY);
296     ASSERT_TRUE(res);
297 
298     const panda_file::File *pf_ptr = nullptr;
299     Runtime::GetCurrent()->GetClassLinker()->EnumeratePandaFiles([&pf_ptr, filename](const panda_file::File &pf) {
300         if (pf.GetFilename() == filename) {
301             pf_ptr = &pf;
302             return false;
303         }
304         return true;
305     });
306 
307     ASSERT(!pf_ptr->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 panda_fname("GetClassIdFromClassHashTableTest.abc");
317     TmpFile aot_fname("GetClassIdFromClassHashTableTest.an");
318 
319     {
320         pandasm::Parser parser;
321         auto res = parser.Parse(GetSourceCode());
322         ASSERT_TRUE(res);
323         ASSERT_TRUE(pandasm::AsmEmitter::Emit(panda_fname.GetFileName(), res.Value()));
324     }
325 
326     auto pfile = panda_file::OpenPandaFile(panda_fname.GetFileName());
327 
328     const uint8_t *descriptor_A = reinterpret_cast<const uint8_t *>("A");
329     const uint8_t *descriptor_B = reinterpret_cast<const uint8_t *>("B");
330     const uint8_t *descriptor_C = reinterpret_cast<const uint8_t *>("C");
331     const uint8_t *descriptor_D = reinterpret_cast<const uint8_t *>("D");
332     const uint8_t *descriptor_E = reinterpret_cast<const uint8_t *>("E");
333 
334     auto class_id1_A = pfile->GetClassId(descriptor_A);
335     auto class_id1_B = pfile->GetClassId(descriptor_B);
336     auto class_id1_C = pfile->GetClassId(descriptor_C);
337     auto class_id1_D = pfile->GetClassId(descriptor_D);
338     auto class_id1_E = pfile->GetClassId(descriptor_E);
339 
340     {
341         auto res = os::exec::Exec(GetPaocFile(), "--gc-type=epsilon", "--paoc-panda-files", panda_fname.GetFileName(),
342                                   "--paoc-output", aot_fname.GetFileName(), "--boot-panda-files", GetPandaStdLibFile());
343         ASSERT_TRUE(res);
344         ASSERT_EQ(res.Value(), 0);
345     }
346 
347     std::string filename = os::GetAbsolutePath(panda_fname.GetFileName());
348     auto res = FileManager::LoadAbcFile(filename, panda_file::File::READ_ONLY);
349     ASSERT_TRUE(res);
350 
351     const panda_file::File *pf_ptr = nullptr;
352     Runtime::GetCurrent()->GetClassLinker()->EnumeratePandaFiles([&pf_ptr, filename](const panda_file::File &pf) {
353         if (pf.GetFilename() == filename) {
354             pf_ptr = &pf;
355             return false;
356         }
357         return true;
358     });
359 
360     auto class_id2_A = pf_ptr->GetClassIdFromClassHashTable(descriptor_A);
361     auto class_id2_B = pf_ptr->GetClassIdFromClassHashTable(descriptor_B);
362     auto class_id2_C = pf_ptr->GetClassIdFromClassHashTable(descriptor_C);
363     auto class_id2_D = pf_ptr->GetClassIdFromClassHashTable(descriptor_D);
364     auto class_id2_E = pf_ptr->GetClassIdFromClassHashTable(descriptor_E);
365 
366     ASSERT_EQ(class_id1_A, class_id2_A);
367     ASSERT_EQ(class_id1_B, class_id2_B);
368     ASSERT_EQ(class_id1_C, class_id2_C);
369     ASSERT_EQ(class_id1_D, class_id2_D);
370     ASSERT_EQ(class_id1_E, class_id2_E);
371 }
372 
373 }  // namespace panda::compiler
374