• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 
16 #include "ecmascript/compiler/file_generators.h"
17 
18 #include "ecmascript/common.h"
19 #include "ecmascript/compiler/aot_file/aot_file_manager.h"
20 #include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
21 #include "ecmascript/platform/code_sign.h"
22 #include "ecmascript/platform/directory.h"
23 #include "ecmascript/snapshot/mem/snapshot.h"
24 #include "ecmascript/stackmap/ark_stackmap_builder.h"
25 #include "ecmascript/stackmap/llvm_stackmap_parser.h"
26 #ifdef COMPILE_MAPLE
27 #include "ecmascript/compiler/litecg_ir_builder.h"
28 #include "ecmascript/compiler/codegen/maple/litecg_codegen.h"
29 #include "ecmascript/stackmap/litecg_stackmap_type.h"
30 #include "ecmascript/compiler/codegen/maple/maple_be/include/litecg/litecg.h"
31 #endif
32 
33 namespace panda::ecmascript::kungfu {
CollectStackMapDes(ModuleSectionDes & des) const34 void Module::CollectStackMapDes(ModuleSectionDes& des) const
35 {
36     uint32_t stackmapSize = des.GetSecSize(ElfSecName::LLVM_STACKMAP);
37     std::unique_ptr<uint8_t[]> stackmapPtr(std::make_unique<uint8_t[]>(stackmapSize));
38     uint64_t addr = des.GetSecAddr(ElfSecName::LLVM_STACKMAP);
39     if (addr == 0) { // assembler stub don't existed llvm stackmap
40         return;
41     }
42     uint64_t textAddr = des.GetSecAddr(ElfSecName::TEXT);
43     if (memcpy_s(stackmapPtr.get(), stackmapSize, reinterpret_cast<void *>(addr), stackmapSize) != EOK) {
44         LOG_COMPILER(FATAL) << "memcpy_s failed";
45         UNREACHABLE();
46     }
47     std::shared_ptr<uint8_t> ptr = nullptr;
48     uint32_t size = 0;
49     ArkStackMapBuilder builder;
50     std::tie(ptr, size) = builder.Run(std::move(stackmapPtr), textAddr, irModule_->GetTriple());
51     des.EraseSec(ElfSecName::LLVM_STACKMAP);
52     des.SetArkStackMapPtr(ptr);
53     des.SetArkStackMapSize(size);
54 }
55 
CollectAnStackMapDes(ModuleSectionDes & des,uint64_t textOffset,CGStackMapInfo & stackMapInfo) const56 void Module::CollectAnStackMapDes(ModuleSectionDes& des, uint64_t textOffset,
57                                   CGStackMapInfo &stackMapInfo) const
58 {
59 #ifdef COMPILE_MAPLE
60     if (!IsLLVM()) {
61         static_cast<LiteCGAssembler*>(assembler_)->CollectAnStackMap(stackMapInfo);
62         return;
63     }
64 #endif
65     uint32_t stackmapSize = des.GetSecSize(ElfSecName::LLVM_STACKMAP);
66     std::unique_ptr<uint8_t[]> stackmapPtr(std::make_unique<uint8_t[]>(stackmapSize));
67     uint64_t addr = des.GetSecAddr(ElfSecName::LLVM_STACKMAP);
68     if (addr == 0) { // assembler stub don't existed llvm stackmap
69         return;
70     }
71     uint64_t textAddr = des.GetSecAddr(ElfSecName::TEXT);
72     if (memcpy_s(stackmapPtr.get(), stackmapSize, reinterpret_cast<void *>(addr), stackmapSize) != EOK) {
73         LOG_COMPILER(FATAL) << "memcpy_s failed";
74         UNREACHABLE();
75     }
76     ArkStackMapBuilder builder;
77     builder.Collect(std::move(stackmapPtr), textAddr, textOffset, stackMapInfo);
78     des.EraseSec(ElfSecName::LLVM_STACKMAP);
79 }
80 
CollectFuncEntryInfo(std::map<uintptr_t,std::string> & addr2name,StubFileInfo & stubInfo,uint32_t moduleIndex,const CompilerLog & log)81 void Module::CollectFuncEntryInfo(std::map<uintptr_t, std::string> &addr2name, StubFileInfo &stubInfo,
82                                   uint32_t moduleIndex, const CompilerLog &log)
83 {
84     if (irModule_->GetModuleKind() != MODULE_LLVM) {
85         std::cout << "CollectFuncEntryInfo is not supported for litecg currently" << std::endl;
86         return;
87     }
88     LLVMModule *llvmModule = static_cast<LLVMModule*>(irModule_);
89     LLVMAssembler *assembler = static_cast<LLVMAssembler*>(assembler_);
90     auto engine = assembler->GetEngine();
91     auto callSigns = llvmModule->GetCSigns();
92     std::vector<uintptr_t> entrys;
93     for (size_t j = 0; j < llvmModule->GetFuncCount(); j++) {
94         LLVMValueRef func = llvmModule->GetFunction(j);
95         ASSERT(func != nullptr);
96         uintptr_t entry = reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(engine, func));
97         entrys.push_back(entry);
98     }
99     auto codeBuff = assembler->GetSectionAddr(ElfSecName::TEXT);
100     const size_t funcCount = llvmModule->GetFuncCount();
101     funcCount_ = funcCount;
102     startIndex_ = stubInfo.GetEntrySize();
103     for (size_t j = 0; j < funcCount; j++) {
104         auto cs = callSigns[j];
105         LLVMValueRef func = llvmModule->GetFunction(j);
106         ASSERT(func != nullptr);
107         int delta = assembler->GetFpDeltaPrevFramSp(func, log);
108         ASSERT(delta >= 0 && (delta % sizeof(uintptr_t) == 0));
109         uint32_t funcSize = 0;
110         if (j < funcCount - 1) {
111             funcSize = entrys[j + 1] - entrys[j];
112         } else {
113             funcSize = codeBuff + assembler->GetSectionSize(ElfSecName::TEXT) - entrys[j];
114         }
115         kungfu::CalleeRegAndOffsetVec info = assembler->GetCalleeReg2Offset(func, log);
116         stubInfo.AddEntry(cs->GetTargetKind(), false, false, cs->GetID(), entrys[j] - codeBuff,
117                           AOTFileManager::STUB_FILE_INDEX, moduleIndex, delta, funcSize, info);
118         ASSERT(!cs->GetName().empty());
119         addr2name[entrys[j]] = cs->GetName();
120     }
121 }
122 
CollectFuncEntryInfo(std::map<uintptr_t,std::string> & addr2name,AnFileInfo & aotInfo,uint32_t fileIndex,uint32_t moduleIndex,const CompilerLog & log)123 void Module::CollectFuncEntryInfo(std::map<uintptr_t, std::string> &addr2name, AnFileInfo &aotInfo, uint32_t fileIndex,
124                                   uint32_t moduleIndex, const CompilerLog &log)
125 {
126 #ifdef COMPILE_MAPLE
127     if (irModule_->GetModuleKind() != MODULE_LLVM) {
128         CollectFuncEntryInfoByLiteCG(addr2name, aotInfo, fileIndex, moduleIndex);
129         return;
130     }
131 #endif
132     LLVMAssembler *assembler = static_cast<LLVMAssembler*>(assembler_);
133     auto engine = assembler->GetEngine();
134     std::vector<std::tuple<uint64_t, size_t, int, bool>> funcInfo; // entry idx delta
135     std::vector<kungfu::CalleeRegAndOffsetVec> calleeSaveRegisters; // entry idx delta
136     // 1.Compile all functions and collect function infos
137     LLVMModule *llvmModule = static_cast<LLVMModule*>(irModule_);
138     llvmModule->IteratefuncIndexMap([&](size_t idx, LLVMValueRef func, bool isFastCall) {
139         uint64_t funcEntry = reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(engine, func));
140         uint64_t length = 0;
141         std::string funcName(LLVMGetValueName2(func, reinterpret_cast<size_t *>(&length)));
142         ASSERT(length != 0);
143         addr2name[funcEntry] = funcName;
144         int delta = assembler->GetFpDeltaPrevFramSp(func, log);
145         ASSERT(delta >= 0 && (delta % sizeof(uintptr_t) == 0));
146         funcInfo.emplace_back(std::tuple(funcEntry, idx, delta, isFastCall));
147         kungfu::CalleeRegAndOffsetVec info = assembler->GetCalleeReg2Offset(func, log);
148         calleeSaveRegisters.emplace_back(info);
149     });
150     // 2.After all functions compiled, the module sections would be fixed
151     uintptr_t textAddr = GetTextAddr();
152     uint32_t textSize = GetTextSize();
153     uintptr_t rodataAddrBeforeText = 0;
154     uint32_t rodataSizeBeforeText = 0;
155     uintptr_t rodataAddrAfterText = 0;
156     uint32_t rodataSizeAfterText = 0;
157     std::tie(rodataAddrBeforeText, rodataSizeBeforeText, rodataAddrAfterText, rodataSizeAfterText) =
158         GetMergedRODataAddrAndSize(textAddr);
159     aotInfo.AlignTextSec(AOTFileInfo::PAGE_ALIGN);
160     if (rodataSizeBeforeText != 0) {
161         aotInfo.UpdateCurTextSecOffset(rodataSizeBeforeText);
162         aotInfo.AlignTextSec(AOTFileInfo::TEXT_SEC_ALIGN);
163     }
164 
165     const size_t funcCount = funcInfo.size();
166     funcCount_ = funcCount;
167     startIndex_ = aotInfo.GetEntrySize();
168     // 3.Add function entries based on the module sections
169     for (size_t i = 0; i < funcInfo.size(); i++) {
170         uint64_t funcEntry;
171         size_t idx;
172         int delta;
173         bool isFastCall;
174         uint32_t funcSize;
175         std::tie(funcEntry, idx, delta, isFastCall) = funcInfo[i];
176         if (i < funcCount - 1) {
177             funcSize = std::get<0>(funcInfo[i + 1]) - funcEntry;
178         } else {
179             funcSize = textAddr + textSize - funcEntry;
180         }
181         auto found = addr2name[funcEntry].find(panda::ecmascript::JSPandaFile::ENTRY_FUNCTION_NAME);
182         bool isMainFunc = found != std::string::npos;
183         uint64_t offset = funcEntry - textAddr + aotInfo.GetCurTextSecOffset();
184         aotInfo.AddEntry(CallSignature::TargetKind::JSFUNCTION, isMainFunc, isFastCall, idx,
185                          offset, fileIndex, moduleIndex, delta, funcSize, calleeSaveRegisters[i]);
186     }
187     aotInfo.UpdateCurTextSecOffset(textSize);
188     if (rodataSizeAfterText != 0) {
189         aotInfo.AlignTextSec(AOTFileInfo::DATA_SEC_ALIGN);
190         aotInfo.UpdateCurTextSecOffset(rodataSizeAfterText);
191     }
192 }
193 
194 #ifdef COMPILE_MAPLE
CollectFuncEntryInfoByLiteCG(std::map<uintptr_t,std::string> & addr2name,AnFileInfo & aotInfo,uint32_t fileIndex,uint32_t moduleIndex)195 void Module::CollectFuncEntryInfoByLiteCG(std::map<uintptr_t, std::string> &addr2name, AnFileInfo &aotInfo,
196                                           uint32_t fileIndex, uint32_t moduleIndex)
197 {
198     std::vector<std::tuple<uint64_t, size_t, int, bool>> funcInfo; // entry idx delta
199     std::vector<kungfu::CalleeRegAndOffsetVec> calleeSaveRegisters; // entry idx delta
200     // 1.Compile all functions and collect function infos
201     LMIRModule *lmirModule = static_cast<LMIRModule*>(irModule_);
202     LiteCGAssembler *assembler = static_cast<LiteCGAssembler*>(assembler_);
203     const auto &func2Addr = assembler->GetCodeInfo().GetFuncInfos();
204     lmirModule->IteratefuncIndexMap([&](size_t idx, std::string funcName, bool isFastCall) {
205         auto itr = func2Addr.find(funcName);
206         if (itr == func2Addr.end()) {
207             LOG_COMPILER(FATAL) << "get function address from emitter failed";
208             UNREACHABLE();
209         }
210         uint64_t funcEntry = itr->second.addr;
211         addr2name[funcEntry] = funcName;
212         int delta = itr->second.fp2PrevFrameSpDelta;
213         ASSERT(delta >= 0 && (delta % sizeof(uintptr_t) == 0));
214         funcInfo.emplace_back(std::tuple(funcEntry, idx, delta, isFastCall));
215         kungfu::CalleeRegAndOffsetVec info = itr->second.calleeRegInfo;
216         calleeSaveRegisters.emplace_back(info);
217     });
218     // 2.After all functions compiled, the module sections would be fixed
219     uint32_t textSize = GetTextSize();
220     uint32_t rodataSizeBeforeText = 0;
221     uint32_t rodataSizeAfterText = 0;
222 
223     aotInfo.AlignTextSec(AOTFileInfo::PAGE_ALIGN);
224     if (rodataSizeBeforeText != 0) {
225         aotInfo.UpdateCurTextSecOffset(rodataSizeBeforeText);
226         aotInfo.AlignTextSec(AOTFileInfo::TEXT_SEC_ALIGN);
227     }
228 
229     const size_t funcCount = funcInfo.size();
230     funcCount_ = funcCount;
231     startIndex_ = aotInfo.GetEntrySize();
232     // 3.Add function entries based on the module sections
233     for (size_t i = 0; i < funcInfo.size(); i++) {
234         uint64_t funcEntry = 0;
235         size_t idx;
236         int delta;
237         bool isFastCall;
238         uint32_t funcSize;
239         std::tie(funcEntry, idx, delta, isFastCall) = funcInfo[i];
240         if (i < funcCount - 1) {
241             funcSize = std::get<0>(funcInfo[i + 1]) - funcEntry;
242         } else {
243             funcSize = textSize - funcEntry;
244         }
245         auto found = addr2name[funcEntry].find(panda::ecmascript::JSPandaFile::ENTRY_FUNCTION_NAME);
246         bool isMainFunc = found != std::string::npos;
247         uint64_t offset = funcEntry;
248         aotInfo.AddEntry(CallSignature::TargetKind::JSFUNCTION, isMainFunc, isFastCall, idx,
249                          offset, fileIndex, moduleIndex, delta, funcSize, calleeSaveRegisters[i]);
250     }
251     aotInfo.UpdateCurTextSecOffset(textSize);
252     if (rodataSizeAfterText != 0) {
253         aotInfo.AlignTextSec(AOTFileInfo::DATA_SEC_ALIGN);
254         aotInfo.UpdateCurTextSecOffset(rodataSizeAfterText);
255     }
256 }
257 #endif
258 
CollectModuleSectionDes(ModuleSectionDes & moduleDes) const259 void Module::CollectModuleSectionDes(ModuleSectionDes &moduleDes) const
260 {
261     if (irModule_->GetModuleKind() != MODULE_LLVM) {
262         std::cout << "CollectModuleSectionDes is not supported for litecg currently" << std::endl;
263         return;
264     }
265     ASSERT(assembler_ != nullptr);
266     LLVMAssembler *assembler = static_cast<LLVMAssembler*>(assembler_);
267     assembler->IterateSecInfos([&](size_t i, std::pair<uint8_t *, size_t> secInfo) {
268         auto curSec = ElfSection(i);
269         ElfSecName sec = curSec.GetElfEnumValue();
270         if (IsRelaSection(sec)) {
271             moduleDes.EraseSec(sec);
272         } else { // aot need relocated; stub don't need collect relocated section
273             moduleDes.SetSecAddrAndSize(sec, reinterpret_cast<uint64_t>(secInfo.first), secInfo.second);
274             moduleDes.SetStartIndex(startIndex_);
275             moduleDes.SetFuncCount(funcCount_);
276         }
277     });
278     CollectStackMapDes(moduleDes);
279 }
280 
CollectAnModuleSectionDes(ModuleSectionDes & moduleDes,uint64_t textOffset,CGStackMapInfo & stackMapInfo) const281 void Module::CollectAnModuleSectionDes(ModuleSectionDes &moduleDes, uint64_t textOffset,
282                                        CGStackMapInfo &stackMapInfo) const
283 {
284     ASSERT(assembler_ != nullptr);
285     assembler_->IterateSecInfos([&](size_t i, std::pair<uint8_t *, size_t> secInfo) {
286         auto curSec = ElfSection(i);
287         ElfSecName sec = curSec.GetElfEnumValue();
288         // aot need relocated; stub don't need collect relocated section
289         moduleDes.SetSecAddrAndSize(sec, reinterpret_cast<uint64_t>(secInfo.first), secInfo.second);
290         moduleDes.SetStartIndex(startIndex_);
291         moduleDes.SetFuncCount(funcCount_);
292     });
293     CollectAnStackMapDes(moduleDes, textOffset, stackMapInfo);
294 }
295 
GetSectionSize(ElfSecName sec) const296 uint32_t Module::GetSectionSize(ElfSecName sec) const
297 {
298     return assembler_->GetSectionSize(sec);
299 }
300 
GetSectionAddr(ElfSecName sec) const301 uintptr_t Module::GetSectionAddr(ElfSecName sec) const
302 {
303     return assembler_->GetSectionAddr(sec);
304 }
305 
RunAssembler(const CompilerLog & log,bool fastCompileMode)306 void Module::RunAssembler(const CompilerLog &log, bool fastCompileMode)
307 {
308     assembler_->Run(log, fastCompileMode);
309 }
310 
DisassemblerFunc(std::map<uintptr_t,std::string> & addr2name,uint64_t textOffset,const CompilerLog & log,const MethodLogList & logList,std::ostringstream & codeStream)311 void Module::DisassemblerFunc(std::map<uintptr_t, std::string> &addr2name, uint64_t textOffset,
312                               const CompilerLog &log, const MethodLogList &logList, std::ostringstream &codeStream)
313 {
314     if (irModule_->GetModuleKind() != MODULE_LLVM) {
315         std::cout << "DisassemblerFunc is not supported for litecg currently" << std::endl;
316         return;
317     }
318     auto *assembler = static_cast<LLVMAssembler*>(assembler_);
319     assembler->Disassemble(addr2name, textOffset, log, logList, codeStream);
320 }
321 
DestroyModule()322 void Module::DestroyModule()
323 {
324     if (irModule_ != nullptr) {
325         delete irModule_;
326         irModule_ = nullptr;
327     }
328     if (assembler_ != nullptr) {
329         delete assembler_;
330         assembler_ = nullptr;
331     }
332 }
333 
CollectAsmStubCodeInfo(std::map<uintptr_t,std::string> & addr2name,uint32_t bridgeModuleIdx)334 void StubFileGenerator::CollectAsmStubCodeInfo(std::map<uintptr_t, std::string> &addr2name, uint32_t bridgeModuleIdx)
335 {
336     uint32_t funSize = 0;
337     for (size_t i = 0; i < asmModule_.GetFunctionCount(); i++) {
338         auto cs = asmModule_.GetCSign(i);
339         auto entryOffset = asmModule_.GetFunction(cs->GetID());
340         if (i < asmModule_.GetFunctionCount() - 1) {
341             auto nextcs = asmModule_.GetCSign(i + 1);
342             funSize = asmModule_.GetFunction(nextcs->GetID()) - entryOffset;
343         } else {
344             funSize = asmModule_.GetBufferSize() - entryOffset;
345         }
346         stubInfo_.AddEntry(cs->GetTargetKind(), false, false, cs->GetID(), entryOffset,
347                            AOTFileManager::STUB_FILE_INDEX, bridgeModuleIdx, 0, funSize);
348         ASSERT(!cs->GetName().empty());
349         addr2name[entryOffset] = cs->GetName();
350     }
351 }
352 
CollectCodeInfo()353 void StubFileGenerator::CollectCodeInfo()
354 {
355     std::map<uintptr_t, std::string> stubAddr2Name;
356     for (size_t i = 0; i < modulePackage_.size(); i++) {
357         modulePackage_[i].CollectFuncEntryInfo(stubAddr2Name, stubInfo_, i, GetLog());
358         ModuleSectionDes des;
359         modulePackage_[i].CollectModuleSectionDes(des);
360         stubInfo_.AddModuleDes(des);
361     }
362     std::map<uintptr_t, std::string> asmAddr2Name;
363     // idx for bridge module is the one after last module in modulePackage
364     CollectAsmStubCodeInfo(asmAddr2Name, modulePackage_.size());
365     if (log_->OutputASM()) {
366         DisassembleAsmStubs(asmAddr2Name);
367         DisassembleEachFunc(stubAddr2Name);
368     }
369 }
370 
DisassembleAsmStubs(std::map<uintptr_t,std::string> & addr2name)371 void StubFileGenerator::DisassembleAsmStubs(std::map<uintptr_t, std::string> &addr2name)
372 {
373     std::string tri = cfg_.GetTripleStr();
374     uint8_t *buf = reinterpret_cast<uint8_t*>(stubInfo_.GetAsmStubAddr());
375     size_t size = stubInfo_.GetAsmStubSize();
376     LLVMAssembler::Disassemble(&addr2name, tri, buf, size);
377 }
378 
RollbackTextSize(Module * module)379 uint64_t AOTFileGenerator::RollbackTextSize(Module *module)
380 {
381     uint64_t textAddr = module->GetSectionAddr(ElfSecName::TEXT);
382     uint32_t textSize = module->GetSectionSize(ElfSecName::TEXT);
383     uint64_t rodataAddrBeforeText = 0;
384     uint32_t rodataSizeBeforeText = 0;
385     uint64_t rodataAddrAfterText = 0;
386     uint32_t rodataSizeAfterText = 0;
387     if (module->IsLLVM()) {
388         // In llvm the ro section is separated from the text section, but these all in text section in LiteCG.
389         std::tie(rodataAddrBeforeText, rodataSizeBeforeText, rodataAddrAfterText, rodataSizeAfterText) =
390             module->GetMergedRODataAddrAndSize(textAddr);
391     }
392     uint64_t textStart = 0;
393     if (rodataSizeAfterText == 0) {
394         textStart = aotInfo_.GetCurTextSecOffset() - textSize;
395     } else {
396         textStart = aotInfo_.GetCurTextSecOffset() - textSize - rodataSizeAfterText;
397         textStart = AlignDown(textStart, AOTFileInfo::DATA_SEC_ALIGN);
398     }
399     return textStart;
400 }
401 
CollectCodeInfo(Module * module,uint32_t moduleIdx)402 void AOTFileGenerator::CollectCodeInfo(Module *module, uint32_t moduleIdx)
403 {
404     std::map<uintptr_t, std::string> addr2name;
405     uint32_t lastEntryIdx = aotInfo_.GetEntrySize();
406     pgo::ApEntityId abcId = INVALID_INDEX;
407     pgo::PGOProfilerManager::GetInstance()->GetPandaFileId(curCompileFileName_.c_str(), abcId);
408     module->CollectFuncEntryInfo(addr2name, aotInfo_, abcId, moduleIdx, GetLog());
409     aotInfo_.MappingEntryFuncsToAbcFiles(curCompileFileName_, lastEntryIdx, aotInfo_.GetEntrySize());
410     ModuleSectionDes des;
411     uint64_t textOffset = RollbackTextSize(module);
412     if (stackMapInfo_ == nullptr) {
413         LOG_ECMA(FATAL) << "stackMapInfo_ isn't be initialized";
414         UNREACHABLE();
415     }
416     module->CollectAnModuleSectionDes(des, textOffset, *stackMapInfo_);
417 
418     aotInfo_.AddModuleDes(des);
419     if (module->IsLLVM() && log_->OutputASM()) {
420         module->DisassemblerFunc(addr2name, textOffset, *(log_), *(logList_), codeStream_);
421     }
422 }
423 
GetLatestModule()424 Module* AOTFileGenerator::GetLatestModule()
425 {
426     return &modulePackage_.back();
427 }
428 
GetModuleVecSize() const429 uint32_t AOTFileGenerator::GetModuleVecSize() const
430 {
431     return modulePackage_.size();
432 }
433 
AddModule(const std::string & name,const std::string & triple,LOptions option,bool logDebug,bool isJit)434 Module* AOTFileGenerator::AddModule(const std::string &name, const std::string &triple,
435                                     [[maybe_unused]] LOptions option, bool logDebug, [[maybe_unused]] bool isJit)
436 {
437 #ifdef COMPILE_MAPLE
438     if (useLiteCG_) {
439         LMIRModule *irModule = new LMIRModule(vm_->GetNativeAreaAllocator(), name, logDebug, triple, isJit);
440         LiteCGAssembler* ass = new LiteCGAssembler(*irModule);
441         modulePackage_.emplace_back(Module(irModule, ass));
442         if (stackMapInfo_ == nullptr) {
443             stackMapInfo_ = new LiteCGStackMapInfo();
444         }
445         return &modulePackage_.back();
446     }
447 #endif
448     LLVMModule* m = new LLVMModule(vm_->GetNativeAreaAllocator(), name, logDebug, triple);
449     LLVMAssembler* ass = new LLVMAssembler(m, option);
450     modulePackage_.emplace_back(Module(m, ass));
451     if (stackMapInfo_ == nullptr) {
452         stackMapInfo_ = new LLVMStackMapInfo();
453     }
454     return &modulePackage_.back();
455 }
456 
AddModule(NativeAreaAllocator * allocator,const std::string & name,const std::string & triple,LOptions option,bool logDebug,StubFileKind kind)457 Module* StubFileGenerator::AddModule(NativeAreaAllocator *allocator, const std::string &name, const std::string &triple,
458                                      LOptions option, bool logDebug, StubFileKind kind)
459 {
460     LLVMModule* m = new LLVMModule(allocator, name, logDebug, triple);
461     if (kind == StubFileKind::BC) {
462         m->SetUpForBytecodeHandlerStubs();
463     } else if (kind == StubFileKind::COM) {
464         m->SetUpForCommonStubs();
465     } else {
466         ASSERT(kind == StubFileKind::BUILTIN);
467         m->SetUpForBuiltinsStubs();
468     }
469     LLVMAssembler* ass = new LLVMAssembler(m, option);
470     modulePackage_.emplace_back(Module(m, ass));
471     return &modulePackage_.back();
472 }
473 
RunAsmAssembler()474 void StubFileGenerator::RunAsmAssembler()
475 {
476     NativeAreaAllocator allocator;
477     Chunk chunk(&allocator);
478     asmModule_.Run(&cfg_, &chunk);
479 
480     auto buffer = asmModule_.GetBuffer();
481     auto bufferSize = asmModule_.GetBufferSize();
482     if (bufferSize == 0U) {
483         return;
484     }
485     stubInfo_.FillAsmStubTempHolder(buffer, bufferSize);
486     stubInfo_.accumulateTotalSize(bufferSize);
487 }
488 
SaveStubFile(const std::string & filename)489 void StubFileGenerator::SaveStubFile(const std::string &filename)
490 {
491     RunLLVMAssembler();
492     RunAsmAssembler();
493     CollectCodeInfo();
494     stubInfo_.Save(filename, cfg_.GetTriple());
495 }
496 
CompileLatestModuleThenDestroy()497 void AOTFileGenerator::CompileLatestModuleThenDestroy()
498 {
499     Module *latestModule = GetLatestModule();
500 #ifdef COMPILE_MAPLE
501     static uint32_t lastModulePC = 0;
502     if (useLiteCG_ && vm_->IsEnableJit()) {
503         lastModulePC = 0;
504     }
505     if (latestModule->GetModule()->GetModuleKind() != MODULE_LLVM) {
506         LMIRModule *lmirModule = static_cast<LMIRModule*>(latestModule->GetModule());
507         lastModulePC = AlignUp(lastModulePC, AOTFileInfo::PAGE_ALIGN);
508         lmirModule->GetModule()->SetLastModulePC(lastModulePC);
509     }
510 #endif
511     uint32_t latestModuleIdx = GetModuleVecSize() - 1;
512     {
513         TimeScope timescope("LLVMIROpt", const_cast<CompilerLog *>(log_));
514         bool fastCompileMode = vm_->GetJSOptions().GetFastAOTCompileMode();
515         latestModule->RunAssembler(*(log_), fastCompileMode);
516     }
517     {
518         TimeScope timescope("LLVMCodeGen", const_cast<CompilerLog *>(log_));
519         CollectCodeInfo(latestModule, latestModuleIdx);
520     }
521     // message has been put into aotInfo, so latestModule could be destroyed
522 #ifdef COMPILE_MAPLE
523     if (latestModule->GetModule()->GetModuleKind() != MODULE_LLVM) {
524         LMIRModule *lmirModule = static_cast<LMIRModule*>(latestModule->GetModule());
525         lastModulePC = lmirModule->GetModule()->GetCurModulePC();
526     }
527 #endif
528     latestModule->DestroyModule();
529 }
530 
DestroyCollectedStackMapInfo()531 void AOTFileGenerator::DestroyCollectedStackMapInfo()
532 {
533     if (stackMapInfo_ != nullptr) {
534         delete stackMapInfo_;
535         stackMapInfo_ = nullptr;
536     }
537 }
538 
GenerateMergedStackmapSection()539 void AOTFileGenerator::GenerateMergedStackmapSection()
540 {
541     ArkStackMapBuilder builder;
542     std::shared_ptr<uint8_t> ptr = nullptr;
543     uint32_t size = 0;
544     if (stackMapInfo_ == nullptr) {
545         LOG_ECMA(FATAL) << "stackMapInfo_ isn't be initialized";
546         UNREACHABLE();
547     }
548     std::tie(ptr, size) = builder.GenerateArkStackMap(*stackMapInfo_, cfg_.GetTriple());
549     aotInfo_.UpdateStackMap(ptr, size, 0);
550     DestroyCollectedStackMapInfo();
551 }
552 
CreateDirIfNotExist(const std::string & filename)553 bool AOTFileGenerator::CreateDirIfNotExist(const std::string &filename)
554 {
555     std::string realPath;
556     if (!panda::ecmascript::RealPath(filename, realPath, false)) {
557         return false;
558     }
559     auto index = realPath.find_last_of('/');
560     if (index == std::string::npos) {
561         return true;
562     }
563     std::string path = realPath.substr(0, index);
564     if (!panda::ecmascript::ForceCreateDirectory(path)) {
565         LOG_COMPILER(ERROR) << "Fail to make dir:" << path;
566         return false;
567     }
568     return panda::ecmascript::SetDirModeAsDefault(path);
569 }
570 
SaveAOTFile(const std::string & filename,const std::string & appSignature)571 void AOTFileGenerator::SaveAOTFile(const std::string &filename, const std::string &appSignature)
572 {
573     if (aotInfo_.GetTotalCodeSize() == 0) {
574         LOG_COMPILER(WARN) << "error: code size of generated an file is empty!";
575         return;
576     }
577     if (!CreateDirIfNotExist(filename)) {
578         LOG_COMPILER(ERROR) << "Fail to access dir:" << filename;
579         return;
580     }
581     PrintMergedCodeComment();
582     GenerateMergedStackmapSection();
583     aotInfo_.GenerateMethodToEntryIndexMap();
584     aotInfo_.Save(filename, cfg_.GetTriple());
585     if (!panda::ecmascript::SetFileModeAsDefault(filename)) {
586         LOG_COMPILER(ERROR) << "Fail to set an file mode:" << filename;
587     }
588     panda::ecmascript::CodeSignatureForAOTFile(filename, appSignature);
589 }
590 
GetMemoryCodeInfos(MachineCodeDesc * machineCodeDesc)591 void AOTFileGenerator::GetMemoryCodeInfos(MachineCodeDesc *machineCodeDesc)
592 {
593     ASSERT(machineCodeDesc != nullptr);
594     if (aotInfo_.GetTotalCodeSize() == 0) {
595         LOG_COMPILER(WARN) << "error: code size of generated an file is empty!";
596         return;
597     }
598     GenerateMergedStackmapSection();
599 
600     // get func entry Map
601     aotInfo_.GenerateMethodToEntryIndexMap();
602 
603     uint64_t funcEntryAddr = reinterpret_cast<uint64_t>(aotInfo_.GetStubs().data());
604     ASSERT(aotInfo_.GetStubs().size() <= 2); // jsfunc + __llvm_deoptimize, 2 : size
605     uint32_t funcEntrySize = sizeof(AOTFileInfo::FuncEntryDes) * aotInfo_.GetStubs().size();
606 
607     ASSERT(aotInfo_.GetModuleSectionDes().size() == 1);
608     auto &moduleSectionDes = aotInfo_.GetModuleSectionDes()[0];
609     // get code data
610     uint64_t textAddr = moduleSectionDes.GetSecAddr(ElfSecName::TEXT);
611     size_t textSize = moduleSectionDes.GetSecSize(ElfSecName::TEXT);
612 
613     uint64_t rodataAddrBeforeText = 0;
614     uint32_t rodataSizeBeforeText = 0;
615     uint64_t rodataAddrAfterText = 0;
616     uint32_t rodataSizeAfterText = 0;
617     std::tie(rodataAddrBeforeText, rodataSizeBeforeText, rodataAddrAfterText, rodataSizeAfterText) =
618         moduleSectionDes.GetMergedRODataAddrAndSize(textAddr);
619 
620     machineCodeDesc->rodataAddrBeforeText = rodataAddrBeforeText;
621     machineCodeDesc->rodataSizeBeforeText = rodataSizeBeforeText;
622     machineCodeDesc->rodataAddrAfterText = rodataAddrAfterText;
623     machineCodeDesc->rodataSizeAfterText = rodataSizeAfterText;
624 
625     uint64_t stackMapPtr = reinterpret_cast<uint64_t>(moduleSectionDes.GetArkStackMapSharePtr().get());
626     size_t stackMapSize = moduleSectionDes.GetArkStackMapSize();
627 
628     machineCodeDesc->codeAddr = textAddr;
629     machineCodeDesc->codeSize = textSize;
630     machineCodeDesc->funcEntryDesAddr = funcEntryAddr;
631     machineCodeDesc->funcEntryDesSize = funcEntrySize;
632     machineCodeDesc->stackMapAddr = stackMapPtr;
633     machineCodeDesc->stackMapSize = stackMapSize;
634 }
635 
JitCreateLitecgModule()636 void AOTFileGenerator::JitCreateLitecgModule()
637 {
638 #ifdef COMPILE_MAPLE
639     Module *latestModule = GetLatestModule();
640     if (latestModule->GetModule()->GetModuleKind() != MODULE_LLVM) {
641         LMIRModule *lmirModule = static_cast<LMIRModule*>(latestModule->GetModule());
642         lmirModule->JitCreateLitecgModule();
643     }
644 #endif
645 }
646 
SaveSnapshotFile()647 void AOTFileGenerator::SaveSnapshotFile()
648 {
649     TimeScope timescope("LLVMCodeGenPass-AI", const_cast<CompilerLog *>(log_));
650     Snapshot snapshot(vm_);
651     const CString snapshotPath(vm_->GetJSOptions().GetAOTOutputFile().c_str());
652     const auto &methodToEntryIndexMap = aotInfo_.GetMethodToEntryIndexMap();
653     PGOTypeManager *ptManager = vm_->GetJSThread()->GetCurrentEcmaContext()->GetPTManager();
654     ptManager->GetAOTSnapshot().ResolveSnapshotData(methodToEntryIndexMap);
655 
656     CString aiPath = snapshotPath + AOTFileManager::FILE_EXTENSION_AI;
657     snapshot.Serialize(aiPath);
658     if (!panda::ecmascript::SetFileModeAsDefault(aiPath.c_str())) {
659         LOG_COMPILER(ERROR) << "Fail to set ai file mode:" << aiPath;
660     }
661 }
662 }  // namespace panda::ecmascript::kungfu
663