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