• 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_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