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_manager.h"
17 #include "os/filesystem.h"
18 #include "events/events.h"
19
20 namespace panda::compiler {
21 class RuntimeInterface;
22
AddFile(const std::string & file_name,RuntimeInterface * runtime,uint32_t gc_type,bool force)23 Expected<bool, std::string> AotManager::AddFile(const std::string &file_name, RuntimeInterface *runtime,
24 uint32_t gc_type, bool force)
25 {
26 if (GetFile(file_name) != nullptr) {
27 LOG(DEBUG, AOT) << "Trying to add already existing AOT file: '" << file_name << "'";
28 return true;
29 }
30 auto aot_file = AotFile::Open(file_name, gc_type);
31 if (!aot_file) {
32 EVENT_AOT_MANAGER(file_name, events::AotManagerAction::OPEN_FAILED);
33 return Unexpected("AotFile::Open failed: " + aot_file.Error());
34 }
35 if (runtime != nullptr) {
36 aot_file.Value()->PatchTable(runtime);
37 aot_file.Value()->InitializeGot(runtime);
38 }
39
40 LOG(DEBUG, AOT) << "AOT file '" << file_name << "' has been loaded, code=" << aot_file.Value()->GetCode()
41 << ", code_size=" << aot_file.Value()->GetCodeSize();
42 LOG(DEBUG, AOT) << " It contains the following panda files:";
43 for (auto header : aot_file.Value()->FileHeaders()) {
44 LOG(DEBUG, AOT) << " " << aot_file.Value()->GetString(header.file_name_str);
45 }
46 aot_files_.push_back(std::move(aot_file.Value()));
47 auto &aot_insert_file = aot_files_[aot_files_.size() - 1];
48 for (auto header : aot_insert_file->FileHeaders()) {
49 auto pf_name = aot_insert_file->GetString(header.file_name_str);
50 auto file_header = aot_insert_file->FindPandaFile(pf_name);
51 if (force) {
52 files_map_[pf_name] = AotPandaFile(aot_insert_file.get(), file_header);
53 } else {
54 files_map_.emplace(std::make_pair(pf_name, AotPandaFile(aot_insert_file.get(), file_header)));
55 }
56 }
57 EVENT_AOT_MANAGER(file_name, events::AotManagerAction::ADDED);
58 return true;
59 }
60
FindPandaFile(const std::string & file_name)61 const AotPandaFile *AotManager::FindPandaFile(const std::string &file_name)
62 {
63 if (file_name.empty()) {
64 return nullptr;
65 }
66 auto it = files_map_.find(file_name);
67 if (it != files_map_.end()) {
68 return &it->second;
69 }
70 return nullptr;
71 }
72
GetFile(const std::string & file_name) const73 const AotFile *AotManager::GetFile(const std::string &file_name) const
74 {
75 auto res = std::find_if(aot_files_.begin(), aot_files_.end(),
76 [&file_name](auto &file) { return file_name == file->GetFileName(); });
77 return res == aot_files_.end() ? nullptr : (*res).get();
78 }
79
80 /* We need such kind of complex print because line length of some tool is limited by 4000 characters */
FancyClassContextPrint(std::string_view context)81 static void FancyClassContextPrint(std::string_view context)
82 {
83 constexpr char DELIMITER = ':';
84 size_t start = 0;
85 size_t end = context.find(DELIMITER, start);
86 while (end != std::string::npos) {
87 LOG(ERROR, AOT) << "\t\t" << context.substr(start, end - start);
88 start = end + 1;
89 end = context.find(DELIMITER, start);
90 }
91 LOG(ERROR, AOT) << "\t\t" << context.substr(start);
92 }
93
CheckFilesInClassContext(std::string_view context,std::string_view aot_context)94 static bool CheckFilesInClassContext(std::string_view context, std::string_view aot_context)
95 {
96 constexpr char DELIMITER = ':';
97 size_t start = 0;
98 size_t end = aot_context.find(DELIMITER, start);
99 while (end != std::string::npos) {
100 auto file_context = aot_context.substr(start, end - start);
101 if (context.find(file_context) == std::string::npos) {
102 LOG(ERROR, AOT) << "Cannot found file " << file_context << " in runtime context";
103 return false;
104 }
105 start = end + 1;
106 end = aot_context.find(DELIMITER, start);
107 }
108 return true;
109 }
110
VerifyClassHierarchy(bool only_boot)111 void AotManager::VerifyClassHierarchy(bool only_boot)
112 {
113 auto complete_context = boot_class_context_;
114 if (!only_boot && !app_class_context_.empty()) {
115 if (!complete_context.empty()) {
116 complete_context.append(":");
117 }
118 complete_context.append(app_class_context_);
119 }
120 auto verify_aot = [this, &complete_context](auto &aot_file) {
121 auto context = aot_file->IsBootPandaFile() ? boot_class_context_ : complete_context;
122 bool is_check = true;
123
124 if (aot_file->IsCompiledWithCha()) {
125 // Aot file context must be prefix of current runtime context
126 if (context.rfind(aot_file->GetClassContext(), 0) != 0) {
127 is_check = false;
128 EVENT_AOT_MANAGER(aot_file->GetFileName(), events::AotManagerAction::CHA_VERIFY_FAILED);
129 }
130 } else {
131 // Aot file context must be contained in current runtime context
132 if (!CheckFilesInClassContext(context, aot_file->GetClassContext())) {
133 is_check = false;
134 EVENT_AOT_MANAGER(aot_file->GetFileName(), events::AotManagerAction::FILE_VERIFY_FAILED);
135 }
136 }
137 if (!is_check) {
138 auto boot_pref = aot_file->IsBootPandaFile() ? "boot " : "";
139 LOG(ERROR, AOT) << "Cannot use " << boot_pref << "AOT file '" << aot_file->GetFileName() << '\'';
140 LOG(ERROR, AOT) << "\tRuntime " << boot_pref << "class context: ";
141 FancyClassContextPrint(context);
142 LOG(ERROR, AOT) << "\tAOT class context: ";
143 FancyClassContextPrint(aot_file->GetClassContext());
144 LOG(FATAL, AOT) << "Aborting due to mismatched class hierarchy";
145 return true;
146 }
147 EVENT_AOT_MANAGER(aot_file->GetFileName(), events::AotManagerAction::VERIFIED);
148 return false;
149 };
150
151 for (auto &cur_aot_file : aot_files_) {
152 verify_aot(cur_aot_file);
153 }
154 }
155
RegisterAotStringRoot(ObjectHeader ** slot,bool is_young)156 void AotManager::RegisterAotStringRoot(ObjectHeader **slot, bool is_young)
157 {
158 os::memory::LockHolder lock(aot_string_roots_lock_);
159 aot_string_gc_roots_.push_back(slot);
160 // Atomic with acquire order reason: data race with aot_string_gc_roots_count_ with dependecies on reads after the
161 // load which should become visible
162 size_t roots_count = aot_string_gc_roots_count_.load(std::memory_order_acquire);
163 if (aot_string_young_set_.size() <= roots_count / MASK_WIDTH) {
164 aot_string_young_set_.push_back(0);
165 }
166 if (is_young) {
167 has_young_aot_string_refs_ = true;
168 aot_string_young_set_[roots_count / MASK_WIDTH] |= 1ULL << (roots_count % MASK_WIDTH);
169 }
170 // Atomic with acq_rel order reason: data race with aot_string_gc_roots_count_ with dependecies on reads after the
171 // load and on writes before the store
172 aot_string_gc_roots_count_.fetch_add(1, std::memory_order_acq_rel);
173 }
174
operator ()(const panda_file::File & pf)175 bool AotClassContextCollector::operator()(const panda_file::File &pf)
176 {
177 if (!acc_->empty()) {
178 acc_->append(":");
179 }
180 acc_->append(os::GetAbsolutePath(pf.GetFilename()));
181 acc_->append("*");
182 acc_->append(std::to_string(pf.GetHeader()->checksum));
183 return true;
184 }
185
186 } // namespace panda::compiler
187