1 /*
2 * Copyright (c) 2021-2025 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(INFO, 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 size_t start = 0;
84 size_t end = context.find(AotClassContextCollector::DELIMETER, start);
85 while (end != std::string::npos) {
86 LOG(ERROR, AOT) << "\t\t" << context.substr(start, end - start);
87 start = end + 1;
88 end = context.find(AotClassContextCollector::DELIMETER, start);
89 }
90 LOG(ERROR, AOT) << "\t\t" << context.substr(start);
91 }
92
CheckFilesInClassContext(std::string_view context,std::string_view aotContext)93 static bool CheckFilesInClassContext(std::string_view context, std::string_view aotContext)
94 {
95 size_t start = 0;
96 size_t end = aotContext.find(AotClassContextCollector::DELIMETER, start);
97 while (end != std::string::npos) {
98 auto fileContext = aotContext.substr(start, end - start);
99 if (context.find(fileContext) == std::string::npos) {
100 LOG(ERROR, AOT) << "Cannot found file " << fileContext << " in runtime context";
101 return false;
102 }
103 start = end + 1;
104 end = aotContext.find(AotClassContextCollector::DELIMETER, start);
105 }
106 return true;
107 }
108
VerifyClassHierarchy()109 void AotManager::VerifyClassHierarchy()
110 {
111 auto completeContext = bootClassContext_;
112 if (!appClassContext_.empty()) {
113 if (!completeContext.empty()) {
114 completeContext.push_back(AotClassContextCollector::DELIMETER);
115 }
116 completeContext.append(appClassContext_);
117 }
118 auto verifyAot = [this, &completeContext](auto &aotFile) {
119 auto context = aotFile->IsBootPandaFile() ? bootClassContext_ : completeContext;
120 bool isCheck = true;
121
122 if (aotFile->IsCompiledWithCha()) {
123 // Aot file context must be prefix of current runtime context
124 if (context.rfind(aotFile->GetClassContext(), 0) != 0) {
125 isCheck = false;
126 EVENT_AOT_MANAGER(aotFile->GetFileName(), events::AotManagerAction::CHA_VERIFY_FAILED);
127 }
128 } else {
129 // Aot file context must be contained in current runtime context
130 if (!CheckFilesInClassContext(context, aotFile->GetClassContext())) {
131 isCheck = false;
132 EVENT_AOT_MANAGER(aotFile->GetFileName(), events::AotManagerAction::FILE_VERIFY_FAILED);
133 }
134 }
135 if (!isCheck) {
136 auto bootPref = aotFile->IsBootPandaFile() ? "boot " : "";
137 LOG(ERROR, AOT) << "Cannot use " << bootPref << "AOT file '" << aotFile->GetFileName() << '\'';
138 LOG(ERROR, AOT) << "\tRuntime " << bootPref << "class context: ";
139 FancyClassContextPrint(context);
140 LOG(ERROR, AOT) << "\tAOT class context: ";
141 FancyClassContextPrint(aotFile->GetClassContext());
142 LOG(FATAL, AOT) << "Aborting due to mismatched class hierarchy";
143 return true;
144 }
145 EVENT_AOT_MANAGER(aotFile->GetFileName(), events::AotManagerAction::VERIFIED);
146 return false;
147 };
148
149 for (auto &curAotFile : aotFiles_) {
150 verifyAot(curAotFile);
151 }
152 }
153
RegisterAotStringRoot(ObjectHeader ** slot,bool isYoung)154 void AotManager::RegisterAotStringRoot(ObjectHeader **slot, bool isYoung)
155 {
156 os::memory::LockHolder lock(aotStringRootsLock_);
157 aotStringGcRoots_.push_back(slot);
158 // Atomic with acquire order reason: data race with aot_string_gc_roots_count_ with dependecies on reads after the
159 // load which should become visible
160 size_t rootsCount = aotStringGcRootsCount_.load(std::memory_order_acquire);
161 if (aotStringYoungSet_.size() <= rootsCount / MASK_WIDTH) {
162 aotStringYoungSet_.push_back(0);
163 }
164 if (isYoung) {
165 hasYoungAotStringRefs_ = true;
166 aotStringYoungSet_[rootsCount / MASK_WIDTH] |= 1ULL << (rootsCount % MASK_WIDTH);
167 }
168 // Atomic with acq_rel order reason: data race with aot_string_gc_roots_count_ with dependecies on reads after the
169 // load and on writes before the store
170 aotStringGcRootsCount_.fetch_add(1, std::memory_order_acq_rel);
171 }
172
ParseClassContextToFile(std::string_view context)173 void AotManager::ParseClassContextToFile(std::string_view context)
174 {
175 size_t start = 0;
176 size_t end;
177 size_t pathEnd;
178 if (context.empty()) {
179 profiledPandaFiles_.insert("");
180 return;
181 }
182 while ((end = context.find(AotClassContextCollector::DELIMETER, start)) != std::string_view::npos) {
183 pathEnd = context.find(AotClassContextCollector::HASH_DELIMETER, start);
184 ASSERT(pathEnd != std::string_view::npos);
185 profiledPandaFiles_.insert(context.substr(start, pathEnd - start));
186 start = end + 1;
187 }
188 pathEnd = context.find(AotClassContextCollector::HASH_DELIMETER, start);
189 ASSERT(pathEnd != std::string_view::npos);
190 profiledPandaFiles_.insert(context.substr(start, pathEnd - start));
191 }
192
operator ()(const panda_file::File & pf)193 bool AotClassContextCollector::operator()(const panda_file::File &pf)
194 {
195 if (!acc_->empty()) {
196 acc_->push_back(DELIMETER);
197 }
198 if (useAbsPath_) {
199 acc_->append(os::GetAbsolutePath(pf.GetFilename()));
200 } else {
201 acc_->append(pf.GetFilename());
202 }
203 acc_->push_back(HASH_DELIMETER);
204 acc_->append(pf.GetPaddedChecksum());
205 return true;
206 }
207
208 } // namespace ark::compiler
209