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 ExecutedMemoryAllocator::DestroyBuf(loadedStub_->GetStubsMem());
44 loadedStub_ = nullptr;
45 }
46
47 for (auto &iter : loadedAn_) {
48 DestroyFileMapMem(iter->GetFileMapMem());
49 }
50 loadedAn_.clear();
51 anFileNameToIndexMap_.clear();
52 }
53
SafeDestroyAnData(const std::string & fileName)54 void AnFileDataManager::SafeDestroyAnData(const std::string &fileName)
55 {
56 WriteLockHolder lock(lock_);
57 std::string anBasename = JSFilePath::GetBaseName(fileName);
58 auto index = UnSafeGetFileInfoIndex(anBasename);
59 if (index == INVALID_INDEX) {
60 return;
61 }
62 auto info = UnSafeGetAnFileInfo(index);
63 info->Destroy();
64 }
65
SafeLoad(const std::string & fileName,Type type)66 bool AnFileDataManager::SafeLoad(const std::string &fileName, Type type)
67 {
68 WriteLockHolder lock(lock_);
69 if (type == Type::STUB) {
70 if (loadedStub_ != nullptr) {
71 return true;
72 }
73 return UnsafeLoadFromStub();
74 } else {
75 const std::shared_ptr<const AOTFileInfo> aotFileInfo = UnsafeFind(fileName);
76 if (aotFileInfo != nullptr) {
77 return true;
78 }
79 return UnsafeLoadFromAOT(fileName);
80 }
81 }
82
UnsafeFind(const std::string & fileName) const83 std::shared_ptr<AnFileInfo> AnFileDataManager::UnsafeFind(const std::string &fileName) const
84 {
85 // note: This method is not thread-safe
86 // need to ensure that the instance of AnFileDataManager has been locked before use
87 const auto iter = anFileNameToIndexMap_.find(fileName);
88 if (iter == anFileNameToIndexMap_.end()) {
89 return nullptr;
90 }
91 uint32_t index = iter->second;
92 return loadedAn_.at(index);
93 }
94
UnsafeLoadFromStub()95 bool AnFileDataManager::UnsafeLoadFromStub()
96 {
97 // note: This method is not thread-safe
98 // need to ensure that the instance of AnFileDataManager has been locked before use
99 loadedStub_ = std::make_shared<StubFileInfo>(StubFileInfo());
100 #if defined(PANDA_TARGET_OHOS)
101 return loadedStub_->MmapLoad();
102 #else
103 return loadedStub_->Load();
104 #endif
105 }
106
Dump() const107 void AnFileDataManager::Dump() const
108 {
109 loadedStub_->Dump();
110 for (const auto& an : loadedAn_) {
111 an->Dump();
112 }
113 }
114
UnsafeLoadFromAOT(const std::string & fileName)115 bool AnFileDataManager::UnsafeLoadFromAOT(const std::string &fileName)
116 {
117 // note: This method is not thread-safe
118 // need to ensure that the instance of AnFileDataManager has been locked before use
119 std::shared_ptr<AnFileInfo> info = std::make_shared<AnFileInfo>(AnFileInfo());
120 if (!info->Load(fileName)) {
121 return false;
122 }
123 std::string anBasename = JSFilePath::GetBaseName(fileName);
124 anFileNameToIndexMap_.insert({anBasename, loadedAn_.size()});
125 loadedAn_.emplace_back(info);
126 return true;
127 }
128
UnSafeGetFileInfoIndex(const std::string & fileName)129 uint32_t AnFileDataManager::UnSafeGetFileInfoIndex(const std::string &fileName)
130 {
131 auto iter = anFileNameToIndexMap_.find(fileName);
132 if (iter == anFileNameToIndexMap_.end()) {
133 return INVALID_INDEX;
134 }
135 return anFileNameToIndexMap_.at(fileName);
136 }
137
SafeGetFileInfoIndex(const std::string & fileName)138 uint32_t AnFileDataManager::SafeGetFileInfoIndex(const std::string &fileName)
139 {
140 ReadLockHolder lock(lock_);
141 return UnSafeGetFileInfoIndex(fileName);
142 }
143
SafeGetAnFileInfo(uint32_t index)144 std::shared_ptr<AnFileInfo> AnFileDataManager::SafeGetAnFileInfo(uint32_t index)
145 {
146 ReadLockHolder lock(lock_);
147 return UnSafeGetAnFileInfo(index);
148 }
149
SafeGetStubFileInfo()150 std::shared_ptr<StubFileInfo> AnFileDataManager::SafeGetStubFileInfo()
151 {
152 ReadLockHolder lock(lock_);
153 return loadedStub_;
154 }
155
156 // Using for cpuprofiler to check if the ReadLock can be held in signal handler, to avoid the reentrancy deadlock.
SafeTryReadLock()157 bool AnFileDataManager::SafeTryReadLock()
158 {
159 // Try to acquire the lock when the signal callback starts to execute. At this time, the vm thread is interrupted,
160 // so the status of whether the lock is held by vm thread will not change until the signal callback ends. If the
161 // attempt is successful, it means that the current vm thread does not hold the lock,the reentrancy problem will
162 // not occur in the callback.
163 if (lock_.TryReadLock()) {
164 lock_.Unlock();
165 return true;
166 }
167 return false;
168 }
169
SafeInsideStub(uintptr_t pc)170 bool AnFileDataManager::SafeInsideStub(uintptr_t pc)
171 {
172 ReadLockHolder lock(lock_);
173 if (loadedStub_ == nullptr) {
174 LOG_COMPILER(ERROR) << "SafeInsideStub: The stub file is not loaded.";
175 return false;
176 }
177
178 uint64_t stubStartAddr = loadedStub_->GetAsmStubAddr();
179 uint64_t stubEndAddr = stubStartAddr + loadedStub_->GetAsmStubSize();
180 if (pc >= stubStartAddr && pc <= stubEndAddr) {
181 return true;
182 }
183
184 const std::vector<ModuleSectionDes> &des = loadedStub_->GetCodeUnits();
185 for (const auto &curDes : des) {
186 if (curDes.ContainCode(pc)) {
187 return true;
188 }
189 }
190
191 return false;
192 }
193
SafeInsideAOT(uintptr_t pc)194 bool AnFileDataManager::SafeInsideAOT(uintptr_t pc)
195 {
196 ReadLockHolder lock(lock_);
197 for (auto &info : loadedAn_) {
198 const std::vector<ModuleSectionDes> &des = info->GetCodeUnits();
199 for (const auto &curDes : des) {
200 if (curDes.ContainCode(pc)) {
201 return true;
202 }
203 }
204 }
205 return false;
206 }
207
SafeCalCallSiteInfo(uintptr_t retAddr)208 AOTFileInfo::CallSiteInfo AnFileDataManager::SafeCalCallSiteInfo(uintptr_t retAddr)
209 {
210 ReadLockHolder lock(lock_);
211 AOTFileInfo::CallSiteInfo callsiteInfo;
212
213 bool ans = false;
214 if (loadedStub_ != nullptr) {
215 ans = loadedStub_->CalCallSiteInfo(retAddr, callsiteInfo);
216 }
217 if (ans) {
218 return callsiteInfo;
219 }
220 // aot
221 for (auto &info : loadedAn_) {
222 ans = info->CalCallSiteInfo(retAddr, callsiteInfo);
223 if (ans) {
224 return callsiteInfo;
225 }
226 }
227 return callsiteInfo;
228 }
229 } // namespace panda::ecmascript
230