• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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/aot_file_manager.h"
16 
17 #include "ecmascript/base/config.h"
18 #include "ecmascript/base/file_header.h"
19 #include "ecmascript/compiler/aot_file/an_file_data_manager.h"
20 #include "ecmascript/compiler/aot_file/elf_builder.h"
21 #include "ecmascript/compiler/aot_file/elf_reader.h"
22 #include "ecmascript/compiler/bc_call_signature.h"
23 #include "ecmascript/compiler/common_stubs.h"
24 #include "ecmascript/compiler/compiler_log.h"
25 #include "ecmascript/deoptimizer/deoptimizer.h"
26 #include "ecmascript/ecma_vm.h"
27 #include "ecmascript/js_file_path.h"
28 #include "ecmascript/js_runtime_options.h"
29 #include "ecmascript/js_thread.h"
30 #include "ecmascript/jspandafile/constpool_value.h"
31 #include "ecmascript/jspandafile/js_pandafile.h"
32 #include "ecmascript/jspandafile/program_object.h"
33 #include "ecmascript/mem/region.h"
34 #include "ecmascript/message_string.h"
35 #include "ecmascript/snapshot/mem/snapshot.h"
36 #include "ecmascript/stackmap/ark_stackmap_parser.h"
37 #include "ecmascript/stackmap/llvm_stackmap_parser.h"
38 
39 namespace panda::ecmascript {
40 using CommonStubCSigns = kungfu::CommonStubCSigns;
41 using BytecodeStubCSigns = kungfu::BytecodeStubCSigns;
42 
Iterate(const RootVisitor & v)43 void AOTFileManager::Iterate(const RootVisitor &v)
44 {
45     for (auto &iter : desCPs_) {
46         for (auto &curCP : iter.second) {
47             v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&iter.second.at(curCP.first))));
48         }
49     }
50 }
51 
DumpAOTInfo()52 void AOTFileManager::DumpAOTInfo()
53 {
54     AnFileDataManager *m = AnFileDataManager::GetInstance();
55     m->Dump();
56 }
57 
LoadStubFile(const std::string & fileName)58 void AOTFileManager::LoadStubFile(const std::string &fileName)
59 {
60     AnFileDataManager *anFileDataManager = AnFileDataManager::GetInstance();
61     if (!anFileDataManager->SafeLoad(fileName, AnFileDataManager::Type::STUB)) {
62         return;
63     }
64     auto info = anFileDataManager->SafeGetStubFileInfo();
65     auto stubs = info->GetStubs();
66     InitializeStubEntries(stubs);
67 }
68 
LoadAnFile(const std::string & fileName)69 bool AOTFileManager::LoadAnFile(const std::string &fileName)
70 {
71     AnFileDataManager *anFileDataManager = AnFileDataManager::GetInstance();
72     return anFileDataManager->SafeLoad(fileName, AnFileDataManager::Type::AOT);
73 }
74 
LoadAiFile(const std::string & filename)75 bool AOTFileManager::LoadAiFile([[maybe_unused]] const std::string &filename)
76 {
77     Snapshot snapshot(vm_);
78 #if !WIN_OR_MAC_OR_IOS_PLATFORM
79     return snapshot.Deserialize(SnapshotType::AI, filename.c_str());
80 #else
81     return true;
82 #endif
83 }
84 
LoadAiFile(const JSPandaFile * jsPandaFile)85 void AOTFileManager::LoadAiFile(const JSPandaFile *jsPandaFile)
86 {
87     uint32_t anFileInfoIndex = GetAnFileIndex(jsPandaFile);
88     // this abc file does not have corresponding an file
89     if (anFileInfoIndex == INVALID_INDEX) {
90         return;
91     }
92 
93     auto iter = desCPs_.find(anFileInfoIndex);
94     // already loaded
95     if (iter != desCPs_.end()) {
96         return;
97     }
98 
99     AnFileDataManager *anFileDataManager = AnFileDataManager::GetInstance();
100     std::string aiFilename = anFileDataManager->GetDir();
101     aiFilename += JSFilePath::GetHapName(jsPandaFile) + AOTFileManager::FILE_EXTENSION_AI;
102     LoadAiFile(aiFilename);
103 }
104 
GetAnFileInfo(const JSPandaFile * jsPandaFile) const105 const std::shared_ptr<AnFileInfo> AOTFileManager::GetAnFileInfo(const JSPandaFile *jsPandaFile) const
106 {
107     uint32_t index = GetAnFileIndex(jsPandaFile);
108     if (index == INVALID_INDEX) {
109         return nullptr;
110     }
111     AnFileDataManager *anFileDataManager = AnFileDataManager::GetInstance();
112     return anFileDataManager->SafeGetAnFileInfo(index);
113 }
114 
IsLoad(const JSPandaFile * jsPandaFile) const115 bool AOTFileManager::IsLoad(const JSPandaFile *jsPandaFile) const
116 {
117     if (!AnFileDataManager::GetInstance()->IsEnable()) {
118         return false;
119     }
120 
121     const std::shared_ptr<AnFileInfo> anFileInfo = GetAnFileInfo(jsPandaFile);
122     if (anFileInfo == nullptr) {
123         return false;
124     }
125     return anFileInfo->IsLoad();
126 }
127 
IsLoadMain(const JSPandaFile * jsPandaFile,const CString & entry) const128 bool AOTFileManager::IsLoadMain(const JSPandaFile *jsPandaFile, const CString &entry) const
129 {
130     if (!jsPandaFile->IsLoadedAOT()) {
131         return false;
132     }
133 
134     const std::shared_ptr<AnFileInfo> anFileInfo = GetAnFileInfo(jsPandaFile);
135     if (anFileInfo == nullptr) {
136         return false;
137     }
138 
139     return anFileInfo->IsLoadMain(jsPandaFile, entry);
140 }
141 
GetAnFileIndex(const JSPandaFile * jsPandaFile) const142 uint32_t AOTFileManager::GetAnFileIndex(const JSPandaFile *jsPandaFile) const
143 {
144     AnFileDataManager *anFileDataManager = AnFileDataManager::GetInstance();
145 
146     // run via command line
147     if (vm_->GetJSOptions().WasAOTOutputFileSet()) {
148         std::string jsPandaFileDesc = jsPandaFile->GetJSPandaFileDesc().c_str();
149         std::string baseName = JSFilePath::GetFileName(jsPandaFileDesc);
150         if (baseName.empty()) {
151             return INVALID_INDEX;
152         }
153         std::string anFileName = baseName + FILE_EXTENSION_AN;
154         return anFileDataManager->SafeGetFileInfoIndex(anFileName);
155     }
156 
157     // run from app hap
158     std::string hapName = JSFilePath::GetHapName(jsPandaFile);
159     if (hapName.empty()) {
160         return INVALID_INDEX;
161     }
162     std::string anFileName = hapName + FILE_EXTENSION_AN;
163     return anFileDataManager->SafeGetFileInfoIndex(anFileName);
164 }
165 
TryReadLock()166 bool AOTFileManager::TryReadLock()
167 {
168     AnFileDataManager *anFileDataManager = AnFileDataManager::GetInstance();
169     return anFileDataManager->SafeTryReadLock();
170 }
171 
InsideStub(uintptr_t pc)172 bool AOTFileManager::InsideStub(uintptr_t pc)
173 {
174     AnFileDataManager *anFileDataManager = AnFileDataManager::GetInstance();
175     return anFileDataManager->SafeInsideStub(pc);
176 }
177 
InsideAOT(uintptr_t pc)178 bool AOTFileManager::InsideAOT(uintptr_t pc)
179 {
180     AnFileDataManager *anFileDataManager = AnFileDataManager::GetInstance();
181     return anFileDataManager->SafeInsideAOT(pc);
182 }
183 
CalCallSiteInfo(uintptr_t retAddr)184 AOTFileInfo::CallSiteInfo AOTFileManager::CalCallSiteInfo(uintptr_t retAddr)
185 {
186     AnFileDataManager *anFileDataManager = AnFileDataManager::GetInstance();
187     return anFileDataManager->SafeCalCallSiteInfo(retAddr);
188 }
189 
PrintAOTEntry(const JSPandaFile * file,const Method * method,uintptr_t entry)190 void AOTFileManager::PrintAOTEntry(const JSPandaFile *file, const Method *method, uintptr_t entry)
191 {
192     uint32_t mId = method->GetMethodId().GetOffset();
193     std::string mName = method->GetMethodName(file);
194     std::string fileName = file->GetFileName();
195     LOG_COMPILER(INFO) << "Bind " << mName << "@" << mId << "@" << fileName
196                        << " -> AOT-Entry = " << reinterpret_cast<void *>(entry);
197 }
198 
SetAOTMainFuncEntry(JSHandle<JSFunction> mainFunc,const JSPandaFile * jsPandaFile,std::string_view entryPoint)199 void AOTFileManager::SetAOTMainFuncEntry(JSHandle<JSFunction> mainFunc, const JSPandaFile *jsPandaFile,
200                                          std::string_view entryPoint)
201 {
202     AnFileDataManager *anFileDataManager = AnFileDataManager::GetInstance();
203     uint32_t anFileInfoIndex = jsPandaFile->GetAOTFileInfoIndex();
204     const std::shared_ptr<AnFileInfo> anFileInfo = anFileDataManager->SafeGetAnFileInfo(anFileInfoIndex);
205     // get main func method
206     auto mainFuncMethodId = jsPandaFile->GetMainMethodIndex(entryPoint.data());
207     uint64_t mainEntry;
208     bool isFastCall;
209     std::tie(mainEntry, isFastCall) = anFileInfo->GetMainFuncEntry(mainFuncMethodId);
210     MethodLiteral *mainMethod = jsPandaFile->FindMethodLiteral(mainFuncMethodId);
211     mainMethod->SetAotCodeBit(true);
212     mainMethod->SetNativeBit(false);
213     Method *method = mainFunc->GetCallTarget();
214     method->SetDeoptThreshold(vm_->GetJSOptions().GetDeoptThreshold());
215     method->SetCodeEntryAndMarkAOT(static_cast<uintptr_t>(mainEntry));
216     method->SetIsFastCall(isFastCall);
217 #ifndef NDEBUG
218     PrintAOTEntry(jsPandaFile, method, mainEntry);
219 #endif
220 }
221 
SetAOTFuncEntry(const JSPandaFile * jsPandaFile,Method * method,uint32_t entryIndex,bool * canFastCall)222 void AOTFileManager::SetAOTFuncEntry(const JSPandaFile *jsPandaFile, Method *method,
223                                      uint32_t entryIndex, bool *canFastCall)
224 {
225     AnFileDataManager *anFileDataManager = AnFileDataManager::GetInstance();
226     uint32_t anFileInfoIndex = jsPandaFile->GetAOTFileInfoIndex();
227     const std::shared_ptr<AnFileInfo> anFileInfo = anFileDataManager->SafeGetAnFileInfo(anFileInfoIndex);
228     const AOTFileInfo::FuncEntryDes &entry = anFileInfo->GetStubDes(entryIndex);
229     uint64_t codeEntry = entry.codeAddr_;
230 #ifndef NDEBUG
231     PrintAOTEntry(jsPandaFile, method, codeEntry);
232 #endif
233     if (!codeEntry) {
234         return;
235     }
236     method->SetDeoptThreshold(vm_->GetJSOptions().GetDeoptThreshold());
237     method->SetCodeEntryAndMarkAOT(codeEntry);
238     method->SetIsFastCall(entry.isFastCall_);
239     if (canFastCall != nullptr) {
240         *canFastCall = entry.isFastCall_;
241     }
242 }
243 
GetStackMapParser() const244 kungfu::ArkStackMapParser *AOTFileManager::GetStackMapParser() const
245 {
246     return arkStackMapParser_;
247 }
248 
AdjustBCStubAndDebuggerStubEntries(JSThread * thread,const std::vector<AOTFileInfo::FuncEntryDes> & stubs,const AsmInterParsedOption & asmInterOpt)249 void AOTFileManager::AdjustBCStubAndDebuggerStubEntries(JSThread *thread,
250                                                         const std::vector<AOTFileInfo::FuncEntryDes> &stubs,
251                                                         const AsmInterParsedOption &asmInterOpt)
252 {
253     auto defaultBCStubDes = stubs[BytecodeStubCSigns::SingleStepDebugging];
254     auto defaultBCDebuggerStubDes = stubs[BytecodeStubCSigns::BCDebuggerEntry];
255     auto defaultBCDebuggerExceptionStubDes = stubs[BytecodeStubCSigns::BCDebuggerExceptionEntry];
256     ASSERT(defaultBCStubDes.kind_ == CallSignature::TargetKind::BYTECODE_HELPER_HANDLER);
257     if (asmInterOpt.handleStart >= 0 && asmInterOpt.handleStart <= asmInterOpt.handleEnd) {
258         for (int i = asmInterOpt.handleStart; i <= asmInterOpt.handleEnd; i++) {
259             thread->SetBCStubEntry(static_cast<size_t>(i), defaultBCStubDes.codeAddr_);
260         }
261 #define DISABLE_SINGLE_STEP_DEBUGGING(name) \
262     thread->SetBCStubEntry(BytecodeStubCSigns::ID_##name, stubs[BytecodeStubCSigns::ID_##name].codeAddr_);
263         INTERPRETER_DISABLE_SINGLE_STEP_DEBUGGING_BC_STUB_LIST(DISABLE_SINGLE_STEP_DEBUGGING)
264 #undef DISABLE_SINGLE_STEP_DEBUGGING
265     }
266     for (size_t i = 0; i < BCStubEntries::EXISTING_BC_HANDLER_STUB_ENTRIES_COUNT; i++) {
267         if (i == BytecodeStubCSigns::ID_ExceptionHandler) {
268             thread->SetBCDebugStubEntry(i, defaultBCDebuggerExceptionStubDes.codeAddr_);
269             continue;
270         }
271         thread->SetBCDebugStubEntry(i, defaultBCDebuggerStubDes.codeAddr_);
272     }
273 }
274 
InitializeStubEntries(const std::vector<AnFileInfo::FuncEntryDes> & stubs)275 void AOTFileManager::InitializeStubEntries(const std::vector<AnFileInfo::FuncEntryDes> &stubs)
276 {
277     auto thread = vm_->GetAssociatedJSThread();
278     size_t len = stubs.size();
279     for (size_t i = 0; i < len; i++) {
280         auto des = stubs[i];
281         if (des.IsCommonStub()) {
282             thread->SetFastStubEntry(des.indexInKindOrMethodId_, des.codeAddr_);
283         } else if (des.IsBCStub()) {
284             thread->SetBCStubEntry(des.indexInKindOrMethodId_, des.codeAddr_);
285 #if ECMASCRIPT_ENABLE_ASM_FILE_LOAD_LOG
286             auto start = GET_MESSAGE_STRING_ID(HandleLdundefined);
287             std::string format = MessageString::GetMessageString(des.indexInKindOrMethodId_ + start);
288             LOG_ECMA(DEBUG) << "bytecode index: " << des.indexInKindOrMethodId_ << " :" << format << " addr: 0x"
289                             << std::hex << des.codeAddr_;
290 #endif
291         } else if (des.IsBuiltinsStub()) {
292             thread->SetBuiltinStubEntry(des.indexInKindOrMethodId_, des.codeAddr_);
293 #if ECMASCRIPT_ENABLE_ASM_FILE_LOAD_LOG
294             int start = GET_MESSAGE_STRING_ID(CharCodeAt);
295             std::string format = MessageString::GetMessageString(des.indexInKindOrMethodId_ + start - 1);  // -1: NONE
296             LOG_ECMA(DEBUG) << "builtins index: " << std::dec << des.indexInKindOrMethodId_ << " :" << format
297                             << " addr: 0x" << std::hex << des.codeAddr_;
298 #endif
299         } else {
300             thread->RegisterRTInterface(des.indexInKindOrMethodId_, des.codeAddr_);
301 #if ECMASCRIPT_ENABLE_ASM_FILE_LOAD_LOG
302             int start = GET_MESSAGE_STRING_ID(CallRuntime);
303             std::string format = MessageString::GetMessageString(des.indexInKindOrMethodId_ + start);
304             LOG_ECMA(DEBUG) << "runtime index: " << std::dec << des.indexInKindOrMethodId_ << " :" << format
305                             << " addr: 0x" << std::hex << des.codeAddr_;
306 #endif
307         }
308     }
309     thread->CheckOrSwitchPGOStubs();
310     AsmInterParsedOption asmInterOpt = vm_->GetJSOptions().GetAsmInterParsedOption();
311     AdjustBCStubAndDebuggerStubEntries(thread, stubs, asmInterOpt);
312 }
313 
RewriteDataSection(uintptr_t dataSec,size_t size,uintptr_t newData,size_t newSize)314 bool AOTFileManager::RewriteDataSection(uintptr_t dataSec, size_t size, uintptr_t newData, size_t newSize)
315 {
316     if (memcpy_s(reinterpret_cast<void *>(dataSec), size, reinterpret_cast<void *>(newData), newSize) != EOK) {
317         LOG_FULL(FATAL) << "memset failed";
318         return false;
319     }
320     return true;
321 }
322 
AddConstantPool(const CString & snapshotFileName,JSTaggedValue deserializedCPList)323 void AOTFileManager::AddConstantPool(const CString &snapshotFileName, JSTaggedValue deserializedCPList)
324 {
325     AnFileDataManager *anFileDataManager = AnFileDataManager::GetInstance();
326     std::string baseName = JSFilePath::GetFileName(snapshotFileName.c_str());
327     uint32_t anFileInfoIndex = anFileDataManager->SafeGetFileInfoIndex(baseName + FILE_EXTENSION_AN);
328 
329     desCPs_.insert({anFileInfoIndex, CMap<int32_t, JSTaggedValue> {}});
330     CMap<int32_t, JSTaggedValue> &cpMap = desCPs_[anFileInfoIndex];
331 
332     JSHandle<TaggedArray> cpList(vm_->GetJSThread(), deserializedCPList);
333     uint32_t len = cpList->GetLength();
334     for (uint32_t pos = 0; pos < len; pos += DESERI_CP_ITEM_SIZE) {
335         int32_t constantPoolID = cpList->Get(pos).GetInt();
336         JSTaggedValue cp = cpList->Get(pos + 1);
337         cpMap.insert({constantPoolID, cp});
338     }
339 }
340 
GetDeserializedConstantPool(const JSPandaFile * jsPandaFile,int32_t cpID)341 JSHandle<JSTaggedValue> AOTFileManager::GetDeserializedConstantPool(const JSPandaFile *jsPandaFile, int32_t cpID)
342 {
343     // The deserialization of the 'ai' data used by the multi-work
344     // is not implemented yet, so there may be a case where
345     // desCPs_ is empty, in which case the Hole will be returned
346     if (desCPs_.empty()) {
347         return JSHandle<JSTaggedValue>(vm_->GetJSThread(), JSTaggedValue::Hole());
348     }
349     uint32_t anFileInfoIndex = jsPandaFile->GetAOTFileInfoIndex();
350     CMap<int32_t, JSTaggedValue> &cpMap = desCPs_.at(anFileInfoIndex);
351     auto iter = cpMap.find(cpID);
352     if (iter == cpMap.end()) {
353         LOG_COMPILER(FATAL) << "can not find deserialized constantpool in anFileInfo, constantPoolID is " << cpID;
354         UNREACHABLE();
355     }
356     return JSHandle<JSTaggedValue>(uintptr_t(&iter->second));
357 }
358 
~AOTFileManager()359 AOTFileManager::~AOTFileManager()
360 {
361     if (arkStackMapParser_ != nullptr) {
362         delete arkStackMapParser_;
363         arkStackMapParser_ = nullptr;
364     }
365 }
366 
AOTFileManager(EcmaVM * vm)367 AOTFileManager::AOTFileManager(EcmaVM *vm) : vm_(vm), factory_(vm->GetFactory())
368 {
369     bool enableLog = vm->GetJSOptions().WasSetCompilerLogOption();
370     arkStackMapParser_ = new kungfu::ArkStackMapParser(enableLog);
371 }
372 
GetAbsolutePath(JSThread * thread,JSTaggedValue relativePathVal)373 JSTaggedValue AOTFileManager::GetAbsolutePath(JSThread *thread, JSTaggedValue relativePathVal)
374 {
375     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
376     CString relativePath = ConvertToString(relativePathVal);
377     CString absPath;
378     if (!GetAbsolutePath(relativePath, absPath)) {
379         LOG_FULL(FATAL) << "Get Absolute Path failed";
380         return JSTaggedValue::Hole();
381     }
382     JSTaggedValue absPathVal = factory->NewFromUtf8(absPath).GetTaggedValue();
383     return absPathVal;
384 }
385 
GetAbsolutePath(const CString & relativePathCstr,CString & absPathCstr)386 bool AOTFileManager::GetAbsolutePath(const CString &relativePathCstr, CString &absPathCstr)
387 {
388     std::string relativePath = ConvertToStdString(relativePathCstr);
389     std::string absPath;
390     if (RealPath(relativePath, absPath)) {
391         absPathCstr = ConvertToString(absPath);
392         return true;
393     }
394     return false;
395 }
396 
GetHeap()397 const Heap *AOTFileManager::GetHeap()
398 {
399     if (vm_ == nullptr) {
400         return nullptr;
401     }
402     return vm_->GetHeap();
403 }
404 }  // namespace panda::ecmascript
405