1 /*
2 * Copyright (c) 2023 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 #include "ecmascript/compiler/aot_file/an_file_data_manager.h"
16 #include "ecmascript/js_file_path.h"
17 #include "ecmascript/mem/c_string.h"
18 #include "ecmascript/platform/file.h"
19
20 namespace panda::ecmascript {
GetInstance()21 AnFileDataManager *AnFileDataManager::GetInstance()
22 {
23 static AnFileDataManager *anFileDataManager = new AnFileDataManager();
24 return anFileDataManager;
25 }
26
~AnFileDataManager()27 AnFileDataManager::~AnFileDataManager()
28 {
29 SafeDestroyAllData();
30 }
31
DestroyFileMapMem(MemMap & fileMapMem)32 void AnFileDataManager::DestroyFileMapMem(MemMap &fileMapMem)
33 {
34 if (fileMapMem.GetOriginAddr() != nullptr && fileMapMem.GetSize() > 0) {
35 FileUnMap(fileMapMem);
36 fileMapMem.Reset();
37 }
38 }
39
SafeDestroyAllData()40 void AnFileDataManager::SafeDestroyAllData()
41 {
42 WriteLockHolder lock(lock_);
43 if (loadedStub_ != nullptr) {
44 loadedStub_->UnregisterFromDebugger();
45 ExecutedMemoryAllocator::DestroyBuf(loadedStub_->GetStubsMem());
46 DestroyFileMapMem(loadedStub_->GetFileMapMem());
47 loadedStub_ = nullptr;
48 }
49
50 for (auto &iter : loadedAn_) {
51 DestroyFileMapMem(iter->GetFileMapMem());
52 }
53 loadedAn_.clear();
54 anFileNameVector_.clear();
55 }
56
SafeDestroyAnData(const std::string & fileName)57 void AnFileDataManager::SafeDestroyAnData(const std::string &fileName)
58 {
59 WriteLockHolder lock(lock_);
60 std::string anBasename = JSFilePath::GetBaseName(fileName);
61 auto index = UnSafeGetFileInfoIndex(anBasename);
62 if (index == INVALID_INDEX) {
63 return;
64 }
65 auto info = UnSafeGetAnFileInfo(index);
66 info->Destroy();
67 }
68
SafeLoad(const std::string & fileName,Type type,std::function<bool (std::string fileName,uint8_t ** buff,size_t * buffSize)> cb)69 bool AnFileDataManager::SafeLoad(const std::string &fileName, Type type, [[maybe_unused]] std::function<bool
70 (std::string fileName, uint8_t **buff, size_t *buffSize)> cb)
71 {
72 WriteLockHolder lock(lock_);
73 if (type == Type::STUB) {
74 if (loadedStub_ != nullptr) {
75 return true;
76 }
77 return UnsafeLoadFromStub(fileName);
78 } else {
79 const std::shared_ptr<const AOTFileInfo> aotFileInfo = UnsafeFind(fileName);
80 if (aotFileInfo != nullptr) {
81 return true;
82 }
83 #if defined(CROSS_PLATFORM) && defined(ANDROID_PLATFORM)
84 return UnsafeLoadFromAOT(fileName, cb);
85 #else
86 return UnsafeLoadFromAOT(fileName);
87 #endif
88 }
89 }
90
UnsafeFind(const std::string & fileName) const91 std::shared_ptr<AnFileInfo> AnFileDataManager::UnsafeFind(const std::string &fileName) const
92 {
93 // note: This method is not thread-safe
94 // need to ensure that the instance of AnFileDataManager has been locked before use
95 const auto iter = std::find(anFileNameVector_.begin(), anFileNameVector_.end(), fileName);
96 if (iter == anFileNameVector_.end()) {
97 return nullptr;
98 }
99 uint32_t index = std::distance(anFileNameVector_.begin(), iter);
100 return loadedAn_.at(index);
101 }
102
UnsafeLoadFromStub(const std::string & fileName)103 bool AnFileDataManager::UnsafeLoadFromStub(const std::string &fileName)
104 {
105 // note: This method is not thread-safe
106 // need to ensure that the instance of AnFileDataManager has been locked before use
107 loadedStub_ = std::make_shared<StubFileInfo>(StubFileInfo());
108 if (!fileName.empty()) {
109 return loadedStub_->MmapLoad(fileName);
110 }
111 #if defined(PANDA_TARGET_OHOS)
112 return loadedStub_->MmapLoad(fileName);
113 #else
114 return loadedStub_->Load();
115 #endif
116 }
117
Dump() const118 void AnFileDataManager::Dump() const
119 {
120 loadedStub_->Dump();
121 for (const auto& an : loadedAn_) {
122 an->Dump();
123 }
124 }
125
UnsafeLoadFromAOTInternal(const std::string & fileName,std::shared_ptr<AnFileInfo> & info)126 bool AnFileDataManager::UnsafeLoadFromAOTInternal(const std::string &fileName, std::shared_ptr<AnFileInfo> &info)
127 {
128 std::string anBasename = JSFilePath::GetBaseName(fileName);
129 anFileNameVector_.emplace_back(anBasename);
130 loadedAn_.emplace_back(info);
131 return true;
132 }
133
UnsafeLoadFromAOT(const std::string & fileName)134 bool AnFileDataManager::UnsafeLoadFromAOT(const std::string &fileName)
135 {
136 // note: This method is not thread-safe
137 // need to ensure that the instance of AnFileDataManager has been locked before use
138 std::shared_ptr<AnFileInfo> info = std::make_shared<AnFileInfo>(AnFileInfo());
139 if (!info->Load(fileName)) {
140 return false;
141 }
142 return UnsafeLoadFromAOTInternal(fileName, info);
143 }
144
145 #if defined(CROSS_PLATFORM) && defined(ANDROID_PLATFORM)
UnsafeLoadFromAOT(const std::string & fileName,std::function<bool (std::string fileName,uint8_t ** buff,size_t * buffSize)> cb)146 bool AnFileDataManager::UnsafeLoadFromAOT(const std::string &fileName, std::function<bool
147 (std::string fileName, uint8_t **buff, size_t *buffSize)> cb)
148 {
149 // note: This method is not thread-safe
150 // need to ensure that the instance of AnFileDataManager has been locked before use
151 std::shared_ptr<AnFileInfo> info = std::make_shared<AnFileInfo>(AnFileInfo());
152 if (!info->Load(fileName, cb)) {
153 return false;
154 }
155 return UnsafeLoadFromAOTInternal(fileName, info);
156 }
157 #endif
158
UnSafeGetFileInfoIndex(const std::string & fileName)159 uint32_t AnFileDataManager::UnSafeGetFileInfoIndex(const std::string &fileName)
160 {
161 const auto iter = std::find(anFileNameVector_.begin(), anFileNameVector_.end(), fileName);
162 if (iter == anFileNameVector_.end()) {
163 return INVALID_INDEX;
164 }
165 return std::distance(anFileNameVector_.begin(), iter);
166 }
167
SafeGetFileInfoIndex(const std::string & fileName)168 uint32_t AnFileDataManager::SafeGetFileInfoIndex(const std::string &fileName)
169 {
170 ReadLockHolder lock(lock_);
171 return UnSafeGetFileInfoIndex(fileName);
172 }
173
SafeGetAnFileInfo(uint32_t index)174 std::shared_ptr<AnFileInfo> AnFileDataManager::SafeGetAnFileInfo(uint32_t index)
175 {
176 ReadLockHolder lock(lock_);
177 return UnSafeGetAnFileInfo(index);
178 }
179
SafeGetStubFileInfo()180 std::shared_ptr<StubFileInfo> AnFileDataManager::SafeGetStubFileInfo()
181 {
182 ReadLockHolder lock(lock_);
183 return loadedStub_;
184 }
185
UnSafeGetAnFileNameNoSuffix(uint32_t index)186 std::string AnFileDataManager::UnSafeGetAnFileNameNoSuffix(uint32_t index)
187 {
188 // The anFileNames are stored in the order of loading. So we can get the an file name by index
189 std::string fileName = anFileNameVector_.at(index);
190 size_t pos = fileName.find_last_of(".");
191 if (pos != std::string::npos) {
192 return fileName.substr(0, pos);
193 }
194 return "";
195 }
196
SafeGetAnFileNameNoSuffix(uint32_t index)197 std::string AnFileDataManager::SafeGetAnFileNameNoSuffix(uint32_t index)
198 {
199 ReadLockHolder lock(lock_);
200 return UnSafeGetAnFileNameNoSuffix(index);
201 }
202
SafeMergeChecksumInfo(const std::unordered_map<CString,uint32_t> & fileNameToChecksumMap)203 void AnFileDataManager::SafeMergeChecksumInfo(const std::unordered_map<CString, uint32_t> &fileNameToChecksumMap)
204 {
205 WriteLockHolder lock(lock_);
206 UnsafeMergeChecksumInfo(fileNameToChecksumMap);
207 }
208
209 // this method is not thread safe,please make sure have lock
UnsafeMergeChecksumInfo(const std::unordered_map<CString,uint32_t> & fileNameToChecksumMap)210 void AnFileDataManager::UnsafeMergeChecksumInfo(const std::unordered_map<CString, uint32_t> &fileNameToChecksumMap)
211 {
212 if (fullFileNameToChecksumMap_.empty()) {
213 fullFileNameToChecksumMap_ = fileNameToChecksumMap;
214 return;
215 }
216 for (const auto &newPair : fileNameToChecksumMap) {
217 bool alreadyHasChecksum = false;
218 for (auto &fullPair : fullFileNameToChecksumMap_) {
219 if (fullPair.first == newPair.first) {
220 alreadyHasChecksum = true;
221 VerifyChecksumOrSetToInvalid(newPair, fullPair);
222 break;
223 }
224 }
225 if (!alreadyHasChecksum) {
226 fullFileNameToChecksumMap_.emplace(newPair.first, newPair.second);
227 }
228 }
229 }
230
VerifyChecksumOrSetToInvalid(const std::pair<CString,uint32_t> & newPair,std::pair<const CString,uint32_t> & fullPair)231 void AnFileDataManager::VerifyChecksumOrSetToInvalid(const std::pair<CString, uint32_t> &newPair,
232 std::pair<const CString, uint32_t> &fullPair)
233 {
234 if (fullPair.second == static_cast<uint32_t>(-1)) {
235 LOG_ECMA(ERROR) << "MergeChecksumInfo fail because checksum is INVALID. "
236 << " file name: " << newPair.first;
237 return;
238 }
239 if (newPair.second != fullPair.second) {
240 LOG_ECMA(ERROR) << "MergeChecksumInfo fail because of different checksum, set to INVALID. "
241 << " file name: " << newPair.first << "old checksum: " << fullPair.second
242 << " new checksum: " << newPair.second;
243 fullPair.second = static_cast<uint32_t>(-1);
244 }
245 }
246
SafeGetfullFileNameToChecksumMap()247 const std::unordered_map<CString, uint32_t> &AnFileDataManager::SafeGetfullFileNameToChecksumMap()
248 {
249 ReadLockHolder lock(lock_);
250 return UnsafeGetfullFileNameToChecksumMap();
251 }
252
UnsafeGetfullFileNameToChecksumMap() const253 const std::unordered_map<CString, uint32_t> &AnFileDataManager::UnsafeGetfullFileNameToChecksumMap() const
254 {
255 return fullFileNameToChecksumMap_;
256 }
257
SafeCheckFilenameToChecksum(const CString & fileName,uint32_t checksum)258 bool AnFileDataManager::SafeCheckFilenameToChecksum(const CString &fileName, uint32_t checksum)
259 {
260 ReadLockHolder lock(lock_);
261 return UnsafeCheckFilenameToChecksum(fileName, checksum);
262 }
263
UnsafeCheckFilenameToChecksum(const CString & fileName,uint32_t checksum)264 bool AnFileDataManager::UnsafeCheckFilenameToChecksum(const CString &fileName, uint32_t checksum)
265 {
266 for (const auto &fileNameToChecksumPair : fullFileNameToChecksumMap_) {
267 if (fileName == fileNameToChecksumPair.first) {
268 if (fileNameToChecksumPair.second == static_cast<uint32_t>(-1) ||
269 fileNameToChecksumPair.second != checksum) {
270 LOG_COMPILER(ERROR) << "an file verify checksum fail: checksum is invalid or different. FileName: "
271 << fileName << " old checksum: " << fileNameToChecksumPair.second
272 << " provided new checksum " << checksum;
273 return false;
274 } else {
275 return true;
276 }
277 }
278 }
279 return true;
280 }
281
282 // Using for cpuprofiler to check if the ReadLock can be held in signal handler, to avoid the reentrancy deadlock.
SafeTryReadLock()283 bool AnFileDataManager::SafeTryReadLock()
284 {
285 // Try to acquire the lock when the signal callback starts to execute. At this time, the vm thread is interrupted,
286 // so the status of whether the lock is held by vm thread will not change until the signal callback ends. If the
287 // attempt is successful, it means that the current vm thread does not hold the lock,the reentrancy problem will
288 // not occur in the callback.
289 if (lock_.TryReadLock()) {
290 lock_.Unlock();
291 return true;
292 }
293 return false;
294 }
295
SafeInsideStub(uintptr_t pc)296 bool AnFileDataManager::SafeInsideStub(uintptr_t pc)
297 {
298 ReadLockHolder lock(lock_);
299 if (loadedStub_ == nullptr) {
300 LOG_COMPILER(ERROR) << "SafeInsideStub: The stub file is not loaded.";
301 return false;
302 }
303
304 uint64_t stubStartAddr = loadedStub_->GetAsmStubAddr();
305 uint64_t stubEndAddr = stubStartAddr + loadedStub_->GetAsmStubSize();
306 if (pc >= stubStartAddr && pc <= stubEndAddr) {
307 return true;
308 }
309
310 const std::vector<ModuleSectionDes> &des = loadedStub_->GetCodeUnits();
311 for (const auto &curDes : des) {
312 if (curDes.ContainCode(pc)) {
313 return true;
314 }
315 }
316
317 return false;
318 }
319
SafeInsideAOT(uintptr_t pc)320 bool AnFileDataManager::SafeInsideAOT(uintptr_t pc)
321 {
322 ReadLockHolder lock(lock_);
323 for (auto &info : loadedAn_) {
324 const std::vector<ModuleSectionDes> &des = info->GetCodeUnits();
325 for (const auto &curDes : des) {
326 if (curDes.ContainCode(pc)) {
327 return true;
328 }
329 }
330 }
331 return false;
332 }
333
SafeCalCallSiteInfo(uintptr_t retAddr,bool isDeopt)334 AOTFileInfo::CallSiteInfo AnFileDataManager::SafeCalCallSiteInfo(uintptr_t retAddr, bool isDeopt)
335 {
336 ReadLockHolder lock(lock_);
337 AOTFileInfo::CallSiteInfo callsiteInfo;
338
339 bool ans = false;
340 if (loadedStub_ != nullptr) {
341 ans = loadedStub_->CalCallSiteInfo(retAddr, callsiteInfo, true, isDeopt);
342 }
343 if (ans) {
344 return callsiteInfo;
345 }
346 // aot
347 for (auto &info : loadedAn_) {
348 ans = info->CalCallSiteInfo(retAddr, callsiteInfo, false, isDeopt);
349 if (ans) {
350 return callsiteInfo;
351 }
352 }
353 return callsiteInfo;
354 }
355 } // namespace panda::ecmascript
356