• 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_file.h"
17 #include "compiler/optimizer/ir/inst.h"
18 #include "optimizer/ir/runtime_interface.h"
19 #include "utils/logger.h"
20 #include "code_info/code_info.h"
21 #include "mem/gc/gc_types.h"
22 #include "trace/trace.h"
23 #include "entrypoints/entrypoints.h"
24 
25 // In some targets, runtime library is not linked, so linker will fail while searching CallStaticPltResolver symbol.
26 // To solve this issue, we define this function as weak.
27 // TODO(msherstennikov): find a better way instead of weak function, e.g. make aot_manager library static.
28 extern "C" void CallStaticPltResolver([[maybe_unused]] void *slot) __attribute__((weak));
CallStaticPltResolver(void * slot)29 extern "C" void CallStaticPltResolver([[maybe_unused]] void *slot) {}
30 
31 namespace panda::compiler {
LoadSymbol(const panda::os::library_loader::LibraryHandle & handle,const char * name)32 static inline Expected<const uint8_t *, std::string> LoadSymbol(const panda::os::library_loader::LibraryHandle &handle,
33                                                                 const char *name)
34 {
35     auto sym = panda::os::library_loader::ResolveSymbol(handle, name);
36     if (!sym) {
37         return Unexpected(sym.Error().ToString());
38     }
39     return reinterpret_cast<uint8_t *>(sym.Value());
40 }
41 
42 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
43 #define LOAD_AOT_SYMBOL(name)                                           \
44     auto name = LoadSymbol(handle, #name);                              \
45     if (!name) {                                                        \
46         return Unexpected("Cannot load name section: " + name.Error()); \
47     }
48 
Open(const std::string & file_name,uint32_t gc_type,bool for_dump)49 Expected<std::unique_ptr<AotFile>, std::string> AotFile::Open(const std::string &file_name, uint32_t gc_type,
50                                                               bool for_dump)
51 {
52     trace::ScopedTrace scoped_trace("Open aot file " + file_name);
53     auto handle_load = panda::os::library_loader::Load(file_name);
54     if (!handle_load) {
55         return Unexpected("AOT elf library open failed: " + handle_load.Error().ToString());
56     }
57     auto handle = std::move(handle_load.Value());
58 
59     LOAD_AOT_SYMBOL(aot);
60     LOAD_AOT_SYMBOL(aot_end);
61     LOAD_AOT_SYMBOL(code);
62     LOAD_AOT_SYMBOL(code_end);
63 
64     if (code_end.Value() < code.Value() || aot_end.Value() <= aot.Value()) {
65         return Unexpected(std::string("Invalid symbols"));
66     }
67 
68     auto aot_header = reinterpret_cast<const AotHeader *>(aot.Value());
69     if (aot_header->magic != MAGIC) {
70         return Unexpected(std::string("Wrong AotHeader magic"));
71     }
72 
73     if (aot_header->version != VERSION) {
74         return Unexpected(std::string("Wrong AotHeader version"));
75     }
76 
77     if (!for_dump && aot_header->environment_checksum != RuntimeInterface::GetEnvironmentChecksum(RUNTIME_ARCH)) {
78         return Unexpected(std::string("Compiler environment checksum mismatch"));
79     }
80 
81     if (!for_dump && aot_header->gc_type != gc_type) {
82         return Unexpected(std::string("Wrong AotHeader gc-type: ") +
83                           std::string(mem::GCStringFromType(static_cast<mem::GCType>(aot_header->gc_type))) + " vs " +
84                           std::string(mem::GCStringFromType(static_cast<mem::GCType>(gc_type))));
85     }
86     return std::make_unique<AotFile>(std::move(handle), Span(aot.Value(), aot_end.Value() - aot.Value()),
87                                      Span(code.Value(), code_end.Value() - code.Value()));
88 }
89 
InitializeGot(RuntimeInterface * runtime)90 void AotFile::InitializeGot(RuntimeInterface *runtime)
91 {
92     size_t minus_first_slot = static_cast<size_t>(RuntimeInterface::IntrinsicId::COUNT) + 1;
93     auto *table = const_cast<uintptr_t *>(
94         reinterpret_cast<const uintptr_t *>(code_.data() - minus_first_slot * PointerSize(RUNTIME_ARCH)));
95 
96     while (*table != 0) {
97         switch (*table) {
98             case AotSlotType::PLT_SLOT:
99                 table -= 2U;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
100                 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
101                 table[1] = reinterpret_cast<uintptr_t>(CallStaticPltResolver);
102                 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
103                 table[2U] = reinterpret_cast<uintptr_t>(
104                     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
105                     table + 1 - runtime->GetCompiledEntryPointOffset(RUNTIME_ARCH) / sizeof(uintptr_t));
106                 break;
107             case AotSlotType::VTABLE_INDEX:
108                 table--;       // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
109                 table[1] = 0;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
110                 break;
111             case AotSlotType::CLASS_SLOT:
112                 table -= 2U;    // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
113                 table[1] = 0;   // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
114                 table[2U] = 0;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
115                 break;
116             case AotSlotType::STRING_SLOT:
117                 table--;       // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
118                 table[1] = 0;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
119                 break;
120             case AotSlotType::INLINECACHE_SLOT:
121                 break;
122             default:
123                 UNREACHABLE();
124                 break;
125         }
126         table--;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
127     }
128 }
129 
PatchTable(RuntimeInterface * runtime)130 void AotFile::PatchTable(RuntimeInterface *runtime)
131 {
132     auto *table = const_cast<uintptr_t *>(reinterpret_cast<const uintptr_t *>(
133         code_.data() - static_cast<size_t>(RuntimeInterface::IntrinsicId::COUNT) * PointerSize(RUNTIME_ARCH)));
134     for (size_t i = 0; i < static_cast<size_t>(RuntimeInterface::IntrinsicId::COUNT); i++) {
135         IntrinsicInst inst(Opcode::Intrinsic, static_cast<RuntimeInterface::IntrinsicId>(i));
136         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
137         table[i] = runtime->GetIntrinsicAddress(inst.IsRuntimeCall(), static_cast<RuntimeInterface::IntrinsicId>(i));
138     }
139 }
140 
GetClass(uint32_t class_id) const141 AotClass AotPandaFile::GetClass(uint32_t class_id) const
142 {
143     auto classes = aot_file_->GetClassHeaders(*header_);
144     auto it = std::lower_bound(classes.begin(), classes.end(), class_id,
145                                [](const auto &a, uintptr_t klass_id) { return a.class_id < klass_id; });
146     if (it == classes.end() || it->class_id != class_id) {
147         return {};
148     }
149     ASSERT(it->methods_count != 0 && "AOT file shall not contain empty classes");
150     return AotClass(aot_file_, &*it);
151 }
152 
FindMethodCodeEntry(size_t index) const153 const void *AotClass::FindMethodCodeEntry(size_t index) const
154 {
155     auto method_header = FindMethodHeader(index);
156     if (method_header == nullptr) {
157         return nullptr;
158     }
159 
160     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
161     return aot_file_->GetMethodCode(method_header) + CodeInfo::GetCodeOffset(RUNTIME_ARCH);
162 }
163 
FindMethodCodeSpan(size_t index) const164 Span<const uint8_t> AotClass::FindMethodCodeSpan(size_t index) const
165 {
166     auto method_header = FindMethodHeader(index);
167     if (method_header == nullptr) {
168         return {};
169     }
170     auto code = Span(aot_file_->GetMethodCode(method_header), method_header->code_size);
171     return CodeInfo(code).GetCodeSpan();
172 }
173 
FindMethodHeader(size_t index) const174 const MethodHeader *AotClass::FindMethodHeader(size_t index) const
175 {
176     auto bitmap = GetBitmap();
177     CHECK_LT(index, bitmap.size());
178     if (!bitmap[index]) {
179         return nullptr;
180     }
181     auto method_index = bitmap.PopCount(index);
182     ASSERT(method_index < header_->methods_count);
183     return aot_file_->GetMethodHeader(header_->methods_offset + method_index);
184 }
185 
GetBitmap() const186 BitVectorSpan AotClass::GetBitmap() const
187 {
188     // TODO(msherstennikov): remove const_cast once BitVector support constant storage
189     auto bitmap_base = const_cast<uint32_t *>(reinterpret_cast<const uint32_t *>(aot_file_->GetMethodsBitmap()));
190     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
191     return BitVectorSpan(bitmap_base + header_->methods_bitmap_offset, header_->methods_bitmap_size);
192 }
193 
194 }  // namespace panda::compiler
195