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_manager.h"
17 #include "os/filesystem.h"
18 #include "events/events.h"
19
20 namespace ark::compiler {
21 class RuntimeInterface;
22
AddFile(const std::string & fileName,RuntimeInterface * runtime,uint32_t gcType,bool force)23 Expected<bool, std::string> AotManager::AddFile(const std::string &fileName, RuntimeInterface *runtime, uint32_t gcType,
24 bool force)
25 {
26 if (GetFile(fileName) != nullptr) {
27 LOG(DEBUG, AOT) << "Trying to add already existing AOT file: '" << fileName << "'";
28 return true;
29 }
30 auto aotFile = AotFile::Open(fileName, gcType);
31 if (!aotFile) {
32 EVENT_AOT_MANAGER(fileName, events::AotManagerAction::OPEN_FAILED);
33 return Unexpected("AotFile::Open failed: " + aotFile.Error());
34 }
35 if (runtime != nullptr) {
36 aotFile.Value()->PatchTable(runtime);
37 aotFile.Value()->InitializeGot(runtime);
38 }
39
40 LOG(DEBUG, AOT) << "AOT file '" << fileName << "' has been loaded, code=" << aotFile.Value()->GetCode()
41 << ", code_size=" << aotFile.Value()->GetCodeSize();
42 LOG(DEBUG, AOT) << " It contains the following panda files:";
43 for (auto header : aotFile.Value()->FileHeaders()) {
44 LOG(DEBUG, AOT) << " " << aotFile.Value()->GetString(header.fileNameStr);
45 }
46 aotFiles_.push_back(std::move(aotFile.Value()));
47 auto &aotInsertFile = aotFiles_[aotFiles_.size() - 1];
48 for (auto header : aotInsertFile->FileHeaders()) {
49 auto pfName = aotInsertFile->GetString(header.fileNameStr);
50 auto fileHeader = aotInsertFile->FindPandaFile(pfName);
51 if (force) {
52 filesMap_[pfName] = AotPandaFile(aotInsertFile.get(), fileHeader);
53 } else {
54 filesMap_.emplace(std::make_pair(pfName, AotPandaFile(aotInsertFile.get(), fileHeader)));
55 }
56 }
57 EVENT_AOT_MANAGER(fileName, events::AotManagerAction::ADDED);
58 return true;
59 }
60
FindPandaFile(const std::string & fileName)61 const AotPandaFile *AotManager::FindPandaFile(const std::string &fileName)
62 {
63 if (fileName.empty()) {
64 return nullptr;
65 }
66 auto it = filesMap_.find(fileName);
67 if (it != filesMap_.end()) {
68 return &it->second;
69 }
70 return nullptr;
71 }
72
GetFile(const std::string & fileName) const73 const AotFile *AotManager::GetFile(const std::string &fileName) const
74 {
75 auto res = std::find_if(aotFiles_.begin(), aotFiles_.end(),
76 [&fileName](auto &file) { return fileName == file->GetFileName(); });
77 return res == aotFiles_.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 aotContext)94 static bool CheckFilesInClassContext(std::string_view context, std::string_view aotContext)
95 {
96 constexpr char DELIMITER = ':';
97 size_t start = 0;
98 size_t end = aotContext.find(DELIMITER, start);
99 while (end != std::string::npos) {
100 auto fileContext = aotContext.substr(start, end - start);
101 if (context.find(fileContext) == std::string::npos) {
102 LOG(ERROR, AOT) << "Cannot found file " << fileContext << " in runtime context";
103 return false;
104 }
105 start = end + 1;
106 end = aotContext.find(DELIMITER, start);
107 }
108 return true;
109 }
110
VerifyClassHierarchy()111 void AotManager::VerifyClassHierarchy()
112 {
113 auto completeContext = bootClassContext_;
114 if (!appClassContext_.empty()) {
115 if (!completeContext.empty()) {
116 completeContext.append(":");
117 }
118 completeContext.append(appClassContext_);
119 }
120 auto verifyAot = [this, &completeContext](auto &aotFile) {
121 auto context = aotFile->IsBootPandaFile() ? bootClassContext_ : completeContext;
122 bool isCheck = true;
123
124 if (aotFile->IsCompiledWithCha()) {
125 // Aot file context must be prefix of current runtime context
126 if (context.rfind(aotFile->GetClassContext(), 0) != 0) {
127 isCheck = false;
128 EVENT_AOT_MANAGER(aotFile->GetFileName(), events::AotManagerAction::CHA_VERIFY_FAILED);
129 }
130 } else {
131 // Aot file context must be contained in current runtime context
132 if (!CheckFilesInClassContext(context, aotFile->GetClassContext())) {
133 isCheck = false;
134 EVENT_AOT_MANAGER(aotFile->GetFileName(), events::AotManagerAction::FILE_VERIFY_FAILED);
135 }
136 }
137 if (!isCheck) {
138 auto bootPref = aotFile->IsBootPandaFile() ? "boot " : "";
139 LOG(ERROR, AOT) << "Cannot use " << bootPref << "AOT file '" << aotFile->GetFileName() << '\'';
140 LOG(ERROR, AOT) << "\tRuntime " << bootPref << "class context: ";
141 FancyClassContextPrint(context);
142 LOG(ERROR, AOT) << "\tAOT class context: ";
143 FancyClassContextPrint(aotFile->GetClassContext());
144 LOG(FATAL, AOT) << "Aborting due to mismatched class hierarchy";
145 return true;
146 }
147 EVENT_AOT_MANAGER(aotFile->GetFileName(), events::AotManagerAction::VERIFIED);
148 return false;
149 };
150
151 for (auto &curAotFile : aotFiles_) {
152 verifyAot(curAotFile);
153 }
154 }
155
RegisterAotStringRoot(ObjectHeader ** slot,bool isYoung)156 void AotManager::RegisterAotStringRoot(ObjectHeader **slot, bool isYoung)
157 {
158 os::memory::LockHolder lock(aotStringRootsLock_);
159 aotStringGcRoots_.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 rootsCount = aotStringGcRootsCount_.load(std::memory_order_acquire);
163 if (aotStringYoungSet_.size() <= rootsCount / MASK_WIDTH) {
164 aotStringYoungSet_.push_back(0);
165 }
166 if (isYoung) {
167 hasYoungAotStringRefs_ = true;
168 aotStringYoungSet_[rootsCount / MASK_WIDTH] |= 1ULL << (rootsCount % 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 aotStringGcRootsCount_.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 if (useAbsPath_) {
181 acc_->append(os::GetAbsolutePath(pf.GetFilename()));
182 } else {
183 acc_->append(pf.GetFilename());
184 }
185 acc_->append("*");
186 acc_->append(pf.GetPaddedChecksum());
187 return true;
188 }
189
190 } // namespace ark::compiler
191