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 os::memory::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 os::memory::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 os::memory::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 return loadedStub_->Load();
101 }
102
Dump() const103 void AnFileDataManager::Dump() const
104 {
105 loadedStub_->Dump();
106 for (const auto& an : loadedAn_) {
107 an->Dump();
108 }
109 }
110
UnsafeLoadFromAOT(const std::string & fileName)111 bool AnFileDataManager::UnsafeLoadFromAOT(const std::string &fileName)
112 {
113 // note: This method is not thread-safe
114 // need to ensure that the instance of AnFileDataManager has been locked before use
115 std::shared_ptr<AnFileInfo> info = std::make_shared<AnFileInfo>(AnFileInfo());
116 if (!info->Load(fileName)) {
117 return false;
118 }
119 std::string anBasename = JSFilePath::GetBaseName(fileName);
120 anFileNameToIndexMap_.insert({anBasename, loadedAn_.size()});
121 loadedAn_.emplace_back(info);
122 return true;
123 }
124
UnSafeGetFileInfoIndex(const std::string & fileName)125 uint32_t AnFileDataManager::UnSafeGetFileInfoIndex(const std::string &fileName)
126 {
127 auto iter = anFileNameToIndexMap_.find(fileName);
128 if (iter == anFileNameToIndexMap_.end()) {
129 return INVALID_INDEX;
130 }
131 return anFileNameToIndexMap_.at(fileName);
132 }
133
SafeGetFileInfoIndex(const std::string & fileName)134 uint32_t AnFileDataManager::SafeGetFileInfoIndex(const std::string &fileName)
135 {
136 os::memory::ReadLockHolder lock(lock_);
137 return UnSafeGetFileInfoIndex(fileName);
138 }
139
SafeGetAnFileInfo(uint32_t index)140 std::shared_ptr<AnFileInfo> AnFileDataManager::SafeGetAnFileInfo(uint32_t index)
141 {
142 os::memory::ReadLockHolder lock(lock_);
143 return UnSafeGetAnFileInfo(index);
144 }
145
SafeGetStubFileInfo()146 std::shared_ptr<StubFileInfo> AnFileDataManager::SafeGetStubFileInfo()
147 {
148 os::memory::ReadLockHolder lock(lock_);
149 return loadedStub_;
150 }
151
152 // Using for cpuprofiler to check if the ReadLock can be held in signal handler, to avoid the reentrancy deadlock.
SafeTryReadLock()153 bool AnFileDataManager::SafeTryReadLock()
154 {
155 // Try to acquire the lock when the signal callback starts to execute. At this time, the vm thread is interrupted,
156 // so the status of whether the lock is held by vm thread will not change until the signal callback ends. If the
157 // attempt is successful, it means that the current vm thread does not hold the lock,the reentrancy problem will
158 // not occur in the callback.
159 if (lock_.TryReadLock()) {
160 lock_.Unlock();
161 return true;
162 }
163 return false;
164 }
165
SafeInsideStub(uintptr_t pc)166 bool AnFileDataManager::SafeInsideStub(uintptr_t pc)
167 {
168 os::memory::ReadLockHolder lock(lock_);
169 if (loadedStub_ == nullptr) {
170 LOG_COMPILER(ERROR) << "SafeInsideStub: The stub file is not loaded.";
171 return false;
172 }
173
174 uint64_t stubStartAddr = loadedStub_->GetAsmStubAddr();
175 uint64_t stubEndAddr = stubStartAddr + loadedStub_->GetAsmStubSize();
176 if (pc >= stubStartAddr && pc <= stubEndAddr) {
177 return true;
178 }
179
180 const std::vector<ModuleSectionDes> &des = loadedStub_->GetCodeUnits();
181 for (const auto &curDes : des) {
182 if (curDes.ContainCode(pc)) {
183 return true;
184 }
185 }
186
187 return false;
188 }
189
SafeInsideAOT(uintptr_t pc)190 bool AnFileDataManager::SafeInsideAOT(uintptr_t pc)
191 {
192 os::memory::ReadLockHolder lock(lock_);
193 for (auto &info : loadedAn_) {
194 const std::vector<ModuleSectionDes> &des = info->GetCodeUnits();
195 for (const auto &curDes : des) {
196 if (curDes.ContainCode(pc)) {
197 return true;
198 }
199 }
200 }
201 return false;
202 }
203
SafeCalCallSiteInfo(uintptr_t retAddr)204 AOTFileInfo::CallSiteInfo AnFileDataManager::SafeCalCallSiteInfo(uintptr_t retAddr)
205 {
206 os::memory::ReadLockHolder lock(lock_);
207 AOTFileInfo::CallSiteInfo callsiteInfo;
208
209 bool ans = false;
210 if (loadedStub_ != nullptr) {
211 ans = loadedStub_->CalCallSiteInfo(retAddr, callsiteInfo);
212 }
213 if (ans) {
214 return callsiteInfo;
215 }
216 // aot
217 for (auto &info : loadedAn_) {
218 ans = info->CalCallSiteInfo(retAddr, callsiteInfo);
219 if (ans) {
220 return callsiteInfo;
221 }
222 }
223 return callsiteInfo;
224 }
225 } // namespace panda::ecmascript
226