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/platform/file.h"
18 
19 namespace panda::ecmascript {
GetInstance()20 AnFileDataManager *AnFileDataManager::GetInstance()
21 {
22     static AnFileDataManager *anFileDataManager = new AnFileDataManager();
23     return anFileDataManager;
24 }
25 
~AnFileDataManager()26 AnFileDataManager::~AnFileDataManager()
27 {
28     SafeDestroyAllData();
29 }
30 
DestroyFileMapMem(MemMap &fileMapMem)31 void AnFileDataManager::DestroyFileMapMem(MemMap &fileMapMem)
32 {
33     if (fileMapMem.GetOriginAddr() != nullptr && fileMapMem.GetSize() > 0) {
34         FileUnMap(fileMapMem);
35         fileMapMem.Reset();
36     }
37 }
38 
SafeDestroyAllData()39 void AnFileDataManager::SafeDestroyAllData()
40 {
41     WriteLockHolder lock(lock_);
42     if (loadedStub_ != nullptr) {
43         loadedStub_->UnregisterFromDebugger();
44         ExecutedMemoryAllocator::DestroyBuf(loadedStub_->GetStubsMem());
45         DestroyFileMapMem(loadedStub_->GetFileMapMem());
46         loadedStub_ = nullptr;
47     }
48 
49     for (auto &iter : loadedAn_) {
50         DestroyFileMapMem(iter->GetFileMapMem());
51     }
52     loadedAn_.clear();
53     anFileNameToIndexMap_.clear();
54 }
55 
SafeDestroyAnData(const std::string &fileName)56 void AnFileDataManager::SafeDestroyAnData(const std::string &fileName)
57 {
58     WriteLockHolder lock(lock_);
59     std::string anBasename = JSFilePath::GetBaseName(fileName);
60     auto index = UnSafeGetFileInfoIndex(anBasename);
61     if (index == INVALID_INDEX) {
62         return;
63     }
64     auto info = UnSafeGetAnFileInfo(index);
65     info->Destroy();
66 }
67 
SafeLoad(const std::string &fileName, Type type, [[maybe_unused]] std::function<bool (std::string fileName, uint8_t **buff, size_t *buffSize)> cb)68 bool AnFileDataManager::SafeLoad(const std::string &fileName, Type type, [[maybe_unused]] std::function<bool
69     (std::string fileName, uint8_t **buff, size_t *buffSize)> cb)
70 {
71     WriteLockHolder lock(lock_);
72     if (type == Type::STUB) {
73         if (loadedStub_ != nullptr) {
74             return true;
75         }
76         return UnsafeLoadFromStub(fileName);
77     } else {
78         const std::shared_ptr<const AOTFileInfo> aotFileInfo = UnsafeFind(fileName);
79         if (aotFileInfo != nullptr) {
80             return true;
81         }
82 #if defined(CROSS_PLATFORM) && defined(ANDROID_PLATFORM)
83         return UnsafeLoadFromAOT(fileName, cb);
84 #else
85         return UnsafeLoadFromAOT(fileName);
86 #endif
87     }
88 }
89 
UnsafeFind(const std::string &fileName) const90 std::shared_ptr<AnFileInfo> AnFileDataManager::UnsafeFind(const std::string &fileName) const
91 {
92     // note: This method is not thread-safe
93     // need to ensure that the instance of AnFileDataManager has been locked before use
94     const auto iter = anFileNameToIndexMap_.find(fileName);
95     if (iter == anFileNameToIndexMap_.end()) {
96         return nullptr;
97     }
98     uint32_t index = iter->second;
99     return loadedAn_.at(index);
100 }
101 
UnsafeLoadFromStub(const std::string &fileName)102 bool AnFileDataManager::UnsafeLoadFromStub(const std::string &fileName)
103 {
104     // note: This method is not thread-safe
105     // need to ensure that the instance of AnFileDataManager has been locked before use
106     loadedStub_ = std::make_shared<StubFileInfo>(StubFileInfo());
107     if (!fileName.empty()) {
108         return loadedStub_->MmapLoad(fileName);
109     }
110 #if defined(PANDA_TARGET_OHOS)
111     return loadedStub_->MmapLoad(fileName);
112 #else
113     return loadedStub_->Load();
114 #endif
115 }
116 
Dump() const117 void AnFileDataManager::Dump() const
118 {
119     loadedStub_->Dump();
120     for (const auto& an : loadedAn_) {
121         an->Dump();
122     }
123 }
124 
UnsafeLoadFromAOTInternal(const std::string &fileName, std::shared_ptr<AnFileInfo> &info)125 bool AnFileDataManager::UnsafeLoadFromAOTInternal(const std::string &fileName, std::shared_ptr<AnFileInfo> &info)
126 {
127     std::string anBasename = JSFilePath::GetBaseName(fileName);
128     anFileNameToIndexMap_.insert({anBasename, loadedAn_.size()});
129     loadedAn_.emplace_back(info);
130     return true;
131 }
132 
UnsafeLoadFromAOT(const std::string &fileName)133 bool AnFileDataManager::UnsafeLoadFromAOT(const std::string &fileName)
134 {
135     // note: This method is not thread-safe
136     // need to ensure that the instance of AnFileDataManager has been locked before use
137     std::shared_ptr<AnFileInfo> info = std::make_shared<AnFileInfo>(AnFileInfo());
138     if (!info->Load(fileName)) {
139         return false;
140     }
141     return UnsafeLoadFromAOTInternal(fileName, info);
142 }
143 
144 #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)145 bool AnFileDataManager::UnsafeLoadFromAOT(const std::string &fileName, std::function<bool
146     (std::string fileName, uint8_t **buff, size_t *buffSize)> cb)
147 {
148     // note: This method is not thread-safe
149     // need to ensure that the instance of AnFileDataManager has been locked before use
150     std::shared_ptr<AnFileInfo> info = std::make_shared<AnFileInfo>(AnFileInfo());
151     if (!info->Load(fileName, cb)) {
152         return false;
153     }
154     return UnsafeLoadFromAOTInternal(fileName, info);
155 }
156 #endif
157 
UnSafeGetFileInfoIndex(const std::string &fileName)158 uint32_t AnFileDataManager::UnSafeGetFileInfoIndex(const std::string &fileName)
159 {
160     auto iter = anFileNameToIndexMap_.find(fileName);
161     if (iter == anFileNameToIndexMap_.end()) {
162         return INVALID_INDEX;
163     }
164     return anFileNameToIndexMap_.at(fileName);
165 }
166 
SafeGetFileInfoIndex(const std::string &fileName)167 uint32_t AnFileDataManager::SafeGetFileInfoIndex(const std::string &fileName)
168 {
169     ReadLockHolder lock(lock_);
170     return UnSafeGetFileInfoIndex(fileName);
171 }
172 
SafeGetAnFileInfo(uint32_t index)173 std::shared_ptr<AnFileInfo> AnFileDataManager::SafeGetAnFileInfo(uint32_t index)
174 {
175     ReadLockHolder lock(lock_);
176     return UnSafeGetAnFileInfo(index);
177 }
178 
SafeGetStubFileInfo()179 std::shared_ptr<StubFileInfo> AnFileDataManager::SafeGetStubFileInfo()
180 {
181     ReadLockHolder lock(lock_);
182     return loadedStub_;
183 }
184 
185 // Using for cpuprofiler to check if the ReadLock can be held in signal handler, to avoid the reentrancy deadlock.
SafeTryReadLock()186 bool AnFileDataManager::SafeTryReadLock()
187 {
188     // Try to acquire the lock when the signal callback starts to execute. At this time, the vm thread is interrupted,
189     // so the status of whether the lock is held by vm thread will not change until the signal callback ends. If the
190     // attempt is successful, it means that the current vm thread does not hold the lock,the reentrancy problem will
191     // not occur in the callback.
192     if (lock_.TryReadLock()) {
193         lock_.Unlock();
194         return true;
195     }
196     return false;
197 }
198 
SafeInsideStub(uintptr_t pc)199 bool AnFileDataManager::SafeInsideStub(uintptr_t pc)
200 {
201     ReadLockHolder lock(lock_);
202     if (loadedStub_ == nullptr) {
203         LOG_COMPILER(ERROR) << "SafeInsideStub: The stub file is not loaded.";
204         return false;
205     }
206 
207     uint64_t stubStartAddr = loadedStub_->GetAsmStubAddr();
208     uint64_t stubEndAddr = stubStartAddr + loadedStub_->GetAsmStubSize();
209     if (pc >= stubStartAddr && pc <= stubEndAddr) {
210         return true;
211     }
212 
213     const std::vector<ModuleSectionDes> &des = loadedStub_->GetCodeUnits();
214     for (const auto &curDes : des) {
215         if (curDes.ContainCode(pc)) {
216             return true;
217         }
218     }
219 
220     return false;
221 }
222 
SafeInsideAOT(uintptr_t pc)223 bool AnFileDataManager::SafeInsideAOT(uintptr_t pc)
224 {
225     ReadLockHolder lock(lock_);
226     for (auto &info : loadedAn_) {
227         const std::vector<ModuleSectionDes> &des = info->GetCodeUnits();
228         for (const auto &curDes : des) {
229             if (curDes.ContainCode(pc)) {
230                 return true;
231             }
232         }
233     }
234     return false;
235 }
236 
SafeCalCallSiteInfo(uintptr_t retAddr, bool isDeopt)237 AOTFileInfo::CallSiteInfo AnFileDataManager::SafeCalCallSiteInfo(uintptr_t retAddr, bool isDeopt)
238 {
239     ReadLockHolder lock(lock_);
240     AOTFileInfo::CallSiteInfo callsiteInfo;
241 
242     bool ans = false;
243     if (loadedStub_ != nullptr) {
244         ans = loadedStub_->CalCallSiteInfo(retAddr, callsiteInfo, true, isDeopt);
245     }
246     if (ans) {
247         return callsiteInfo;
248     }
249     // aot
250     for (auto &info : loadedAn_) {
251         ans = info->CalCallSiteInfo(retAddr, callsiteInfo, false, isDeopt);
252         if (ans) {
253             return callsiteInfo;
254         }
255     }
256     return callsiteInfo;
257 }
258 }  // namespace panda::ecmascript
259