• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     anFileNameToIndexMap_.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 = anFileNameToIndexMap_.find(fileName);
96     if (iter == anFileNameToIndexMap_.end()) {
97         return nullptr;
98     }
99     uint32_t index = iter->second;
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     anFileNameToIndexMap_.insert({anBasename, loadedAn_.size()});
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     auto iter = anFileNameToIndexMap_.find(fileName);
162     if (iter == anFileNameToIndexMap_.end()) {
163         return INVALID_INDEX;
164     }
165     return anFileNameToIndexMap_.at(fileName);
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 
SafeMergeChecksumInfo(const std::unordered_map<CString,uint32_t> & fileNameToChecksumMap)186 void AnFileDataManager::SafeMergeChecksumInfo(const std::unordered_map<CString, uint32_t> &fileNameToChecksumMap)
187 {
188     WriteLockHolder lock(lock_);
189     UnsafeMergeChecksumInfo(fileNameToChecksumMap);
190 }
191 
192 // this method is not thread safe,please make sure have lock
UnsafeMergeChecksumInfo(const std::unordered_map<CString,uint32_t> & fileNameToChecksumMap)193 void AnFileDataManager::UnsafeMergeChecksumInfo(const std::unordered_map<CString, uint32_t> &fileNameToChecksumMap)
194 {
195     if (fullFileNameToChecksumMap_.empty()) {
196         fullFileNameToChecksumMap_ = fileNameToChecksumMap;
197         return;
198     }
199     for (const auto &newPair : fileNameToChecksumMap) {
200         bool alreadyHasChecksum = false;
201         for (auto &fullPair : fullFileNameToChecksumMap_) {
202             if (fullPair.first == newPair.first) {
203                 alreadyHasChecksum = true;
204                 VerifyChecksumOrSetToInvalid(newPair, fullPair);
205                 break;
206             }
207         }
208         if (!alreadyHasChecksum) {
209             fullFileNameToChecksumMap_.emplace(newPair.first, newPair.second);
210         }
211     }
212 }
213 
VerifyChecksumOrSetToInvalid(const std::pair<CString,uint32_t> & newPair,std::pair<const CString,uint32_t> & fullPair)214 void AnFileDataManager::VerifyChecksumOrSetToInvalid(const std::pair<CString, uint32_t> &newPair,
215                                                      std::pair<const CString, uint32_t> &fullPair)
216 {
217     if (fullPair.second == static_cast<uint32_t>(-1)) {
218         LOG_ECMA(ERROR) << "MergeChecksumInfo fail because checksum is INVALID. "
219                         << " file name: " << newPair.first;
220         return;
221     }
222     if (newPair.second != fullPair.second) {
223         LOG_ECMA(ERROR) << "MergeChecksumInfo fail because of different checksum, set to INVALID. "
224                         << " file name: " << newPair.first << "old checksum: " << fullPair.second
225                         << " new checksum: " << newPair.second;
226         fullPair.second = static_cast<uint32_t>(-1);
227     }
228 }
229 
SafeGetfullFileNameToChecksumMap()230 const std::unordered_map<CString, uint32_t> &AnFileDataManager::SafeGetfullFileNameToChecksumMap()
231 {
232     ReadLockHolder lock(lock_);
233     return UnsafeGetfullFileNameToChecksumMap();
234 }
235 
UnsafeGetfullFileNameToChecksumMap() const236 const std::unordered_map<CString, uint32_t> &AnFileDataManager::UnsafeGetfullFileNameToChecksumMap() const
237 {
238     return fullFileNameToChecksumMap_;
239 }
240 
SafeCheckFilenameToChecksum(const CString & fileName,uint32_t checksum)241 bool AnFileDataManager::SafeCheckFilenameToChecksum(const CString &fileName, uint32_t checksum)
242 {
243     ReadLockHolder lock(lock_);
244     return UnsafeCheckFilenameToChecksum(fileName, checksum);
245 }
246 
UnsafeCheckFilenameToChecksum(const CString & fileName,uint32_t checksum)247 bool AnFileDataManager::UnsafeCheckFilenameToChecksum(const CString &fileName, uint32_t checksum)
248 {
249     for (const auto &fileNameToChecksumPair : fullFileNameToChecksumMap_) {
250         if (fileName == fileNameToChecksumPair.first) {
251             if (fileNameToChecksumPair.second == static_cast<uint32_t>(-1) ||
252                 fileNameToChecksumPair.second != checksum) {
253                 LOG_COMPILER(ERROR) << "an file verify checksum fail: checksum is invalid or different. FileName: "
254                                     << fileName << " old checksum: " << fileNameToChecksumPair.second
255                                     << " provided new checksum " << checksum;
256                 return false;
257             } else {
258                 return true;
259             }
260         }
261     }
262     return true;
263 }
264 
265 // Using for cpuprofiler to check if the ReadLock can be held in signal handler, to avoid the reentrancy deadlock.
SafeTryReadLock()266 bool AnFileDataManager::SafeTryReadLock()
267 {
268     // Try to acquire the lock when the signal callback starts to execute. At this time, the vm thread is interrupted,
269     // so the status of whether the lock is held by vm thread will not change until the signal callback ends. If the
270     // attempt is successful, it means that the current vm thread does not hold the lock,the reentrancy problem will
271     // not occur in the callback.
272     if (lock_.TryReadLock()) {
273         lock_.Unlock();
274         return true;
275     }
276     return false;
277 }
278 
SafeInsideStub(uintptr_t pc)279 bool AnFileDataManager::SafeInsideStub(uintptr_t pc)
280 {
281     ReadLockHolder lock(lock_);
282     if (loadedStub_ == nullptr) {
283         LOG_COMPILER(ERROR) << "SafeInsideStub: The stub file is not loaded.";
284         return false;
285     }
286 
287     uint64_t stubStartAddr = loadedStub_->GetAsmStubAddr();
288     uint64_t stubEndAddr = stubStartAddr + loadedStub_->GetAsmStubSize();
289     if (pc >= stubStartAddr && pc <= stubEndAddr) {
290         return true;
291     }
292 
293     const std::vector<ModuleSectionDes> &des = loadedStub_->GetCodeUnits();
294     for (const auto &curDes : des) {
295         if (curDes.ContainCode(pc)) {
296             return true;
297         }
298     }
299 
300     return false;
301 }
302 
SafeInsideAOT(uintptr_t pc)303 bool AnFileDataManager::SafeInsideAOT(uintptr_t pc)
304 {
305     ReadLockHolder lock(lock_);
306     for (auto &info : loadedAn_) {
307         const std::vector<ModuleSectionDes> &des = info->GetCodeUnits();
308         for (const auto &curDes : des) {
309             if (curDes.ContainCode(pc)) {
310                 return true;
311             }
312         }
313     }
314     return false;
315 }
316 
SafeCalCallSiteInfo(uintptr_t retAddr,bool isDeopt)317 AOTFileInfo::CallSiteInfo AnFileDataManager::SafeCalCallSiteInfo(uintptr_t retAddr, bool isDeopt)
318 {
319     ReadLockHolder lock(lock_);
320     AOTFileInfo::CallSiteInfo callsiteInfo;
321 
322     bool ans = false;
323     if (loadedStub_ != nullptr) {
324         ans = loadedStub_->CalCallSiteInfo(retAddr, callsiteInfo, true, isDeopt);
325     }
326     if (ans) {
327         return callsiteInfo;
328     }
329     // aot
330     for (auto &info : loadedAn_) {
331         ans = info->CalCallSiteInfo(retAddr, callsiteInfo, false, isDeopt);
332         if (ans) {
333             return callsiteInfo;
334         }
335     }
336     return callsiteInfo;
337 }
338 }  // namespace panda::ecmascript
339