• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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/codegen/llvm/llvm_codegen.h"
17 #if defined(PANDA_TARGET_MACOS) || defined(PANDA_TARGET_IOS)
18 #include "ecmascript/base/llvm_helper.h"
19 #endif
20 
21 #include <cstring>
22 #include <iomanip>
23 #include <vector>
24 
25 #if defined(__clang__)
26 #pragma clang diagnostic push
27 #pragma clang diagnostic ignored "-Wshadow"
28 #pragma clang diagnostic ignored "-Wunused-parameter"
29 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
30 #elif defined(__GNUC__)
31 #pragma GCC diagnostic push
32 #pragma GCC diagnostic ignored "-Wshadow"
33 #pragma GCC diagnostic ignored "-Wunused-parameter"
34 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
35 #endif
36 
37 #include "llvm-c/Analysis.h"
38 #include "llvm-c/Disassembler.h"
39 #include "llvm-c/DisassemblerTypes.h"
40 #include "llvm-c/Target.h"
41 #include "llvm-c/Transforms/PassManagerBuilder.h"
42 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
43 #include "llvm/DebugInfo/DIContext.h"
44 #include "llvm/ExecutionEngine/ExecutionEngine.h"
45 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
46 #include "llvm/ExecutionEngine/MCJIT.h"
47 #include "llvm/IR/LegacyPassManager.h"
48 #include "llvm/IR/Verifier.h"
49 #include "lib/llvm_interface.h"
50 
51 #include "ecmascript/compiler/aot_file/aot_file_info.h"
52 #include "ecmascript/compiler/call_signature.h"
53 #include "ecmascript/compiler/codegen/llvm/llvm_ir_builder.h"
54 #include "ecmascript/compiler/compiler_log.h"
55 #include "ecmascript/compiler/debug_info.h"
56 #include "ecmascript/ecma_macros.h"
57 #include "ecmascript/mem/region.h"
58 #include "ecmascript/object_factory.h"
59 #include "ecmascript/stackmap/llvm/llvm_stackmap_parser.h"
60 
61 #if defined(__clang__)
62 #pragma clang diagnostic pop
63 #elif defined(__GNUC__)
64 #pragma GCC diagnostic pop
65 #endif
66 
67 namespace panda::ecmascript::kungfu {
68 using namespace panda::ecmascript;
69 using namespace llvm;
70 
CodeInfo(CodeSpaceOnDemand & codeSpaceOnDemand)71 CodeInfo::CodeInfo(CodeSpaceOnDemand &codeSpaceOnDemand) : codeSpaceOnDemand_(codeSpaceOnDemand)
72 {
73     secInfos_.fill(std::make_pair(nullptr, 0));
74 }
75 
~CodeInfo()76 CodeInfo::~CodeInfo()
77 {
78     Reset();
79 }
80 
GetInstance()81 CodeInfo::CodeSpace *CodeInfo::CodeSpace::GetInstance()
82 {
83     static CodeSpace *codeSpace = new CodeSpace();
84     return codeSpace;
85 }
86 
CodeSpace()87 CodeInfo::CodeSpace::CodeSpace()
88 {
89     ASSERT(REQUIRED_SECS_LIMIT == AlignUp(REQUIRED_SECS_LIMIT, PageSize()));
90     reqSecs_ = static_cast<uint8_t *>(PageMap(REQUIRED_SECS_LIMIT, PAGE_PROT_READWRITE).GetMem());
91     if (reqSecs_ == reinterpret_cast<uint8_t *>(-1)) {
92         reqSecs_ = nullptr;
93     }
94     ASSERT(UNREQUIRED_SECS_LIMIT == AlignUp(UNREQUIRED_SECS_LIMIT, PageSize()));
95     unreqSecs_ = static_cast<uint8_t *>(PageMap(UNREQUIRED_SECS_LIMIT, PAGE_PROT_READWRITE).GetMem());
96     if (unreqSecs_ == reinterpret_cast<uint8_t *>(-1)) {
97         unreqSecs_ = nullptr;
98     }
99 }
100 
~CodeSpace()101 CodeInfo::CodeSpace::~CodeSpace()
102 {
103     reqBufPos_ = 0;
104     unreqBufPos_ = 0;
105     if (reqSecs_ != nullptr) {
106         PageUnmap(MemMap(reqSecs_, REQUIRED_SECS_LIMIT));
107     }
108     reqSecs_ = nullptr;
109     if (unreqSecs_ != nullptr) {
110         PageUnmap(MemMap(unreqSecs_, UNREQUIRED_SECS_LIMIT));
111     }
112     unreqSecs_ = nullptr;
113 }
114 
Alloca(uintptr_t size,bool isReq,size_t alignSize)115 uint8_t *CodeInfo::CodeSpace::Alloca(uintptr_t size, bool isReq, size_t alignSize)
116 {
117     uint8_t *addr = nullptr;
118     auto bufBegin = isReq ? reqSecs_ : unreqSecs_;
119     auto &curPos = isReq ? reqBufPos_ : unreqBufPos_;
120     size_t limit = isReq ? REQUIRED_SECS_LIMIT : UNREQUIRED_SECS_LIMIT;
121     if (curPos + size > limit) {
122         LOG_COMPILER(ERROR) << std::hex << "Alloca Section failed. Current curPos:" << curPos
123                             << " plus size:" << size << "exceed limit:" << limit;
124         exit(-1);
125     }
126     if (alignSize > 0) {
127         curPos = AlignUp(curPos, alignSize);
128     }
129     addr = bufBegin + curPos;
130     curPos += size;
131     return addr;
132 }
133 
Alloca(uintptr_t size,bool isReq,size_t alignSize)134 uint8_t *CodeInfo::CodeSpaceOnDemand::Alloca(uintptr_t size, [[maybe_unused]] bool isReq, size_t alignSize)
135 {
136     // Always apply for an aligned memory block here.
137     auto alignedSize = alignSize > 0 ? AlignUp(size, alignSize) : size;
138     // Verify the size and temporarily use REQUIREd_SECS.LIMITED as the online option, allowing for adjustments.
139     if (alignedSize > SECTION_LIMIT) {
140         LOG_COMPILER(FATAL) << std::hex << "invalid memory size: " << alignedSize;
141         return nullptr;
142     }
143     uint8_t *addr = static_cast<uint8_t *>(malloc(alignedSize));
144     if (addr == nullptr) {
145         LOG_COMPILER(FATAL) << "malloc section failed.";
146         return nullptr;
147     }
148     sections_.push_back({addr, alignedSize});
149     return addr;
150 }
151 
~CodeSpaceOnDemand()152 CodeInfo::CodeSpaceOnDemand::~CodeSpaceOnDemand()
153 {
154     // release all used memory.
155     for (auto &section : sections_) {
156         if ((section.first != nullptr) && (section.second != 0)) {
157             free(section.first);
158         }
159     }
160     sections_.clear();
161 }
162 
AllocaOnDemand(uintptr_t size,size_t alignSize)163 uint8_t *CodeInfo::AllocaOnDemand(uintptr_t size, size_t alignSize)
164 {
165     return codeSpaceOnDemand_.Alloca(size, true, alignSize);
166 }
167 
AllocaInReqSecBuffer(uintptr_t size,size_t alignSize)168 uint8_t *CodeInfo::AllocaInReqSecBuffer(uintptr_t size, size_t alignSize)
169 {
170     return CodeSpace::GetInstance()->Alloca(size, true, alignSize);
171 }
172 
AllocaInNotReqSecBuffer(uintptr_t size,size_t alignSize)173 uint8_t *CodeInfo::AllocaInNotReqSecBuffer(uintptr_t size, size_t alignSize)
174 {
175     return CodeSpace::GetInstance()->Alloca(size, false, alignSize);
176 }
177 
AllocaCodeSectionImp(uintptr_t size,const char * sectionName,AllocaSectionCallback allocaInReqSecBuffer)178 uint8_t *CodeInfo::AllocaCodeSectionImp(uintptr_t size, const char *sectionName,
179                                         AllocaSectionCallback allocaInReqSecBuffer)
180 {
181     uint8_t *addr = nullptr;
182     auto curSec = ElfSection(sectionName);
183     if (curSec.isValidAOTSec()) {
184         if (!alreadyPageAlign_) {
185             addr = (this->*allocaInReqSecBuffer)(size, AOTFileInfo::PAGE_ALIGN);
186             alreadyPageAlign_ = true;
187         } else {
188             addr = (this->*allocaInReqSecBuffer)(size, AOTFileInfo::TEXT_SEC_ALIGN);
189         }
190     } else {
191         addr = (this->*allocaInReqSecBuffer)(size, 0);
192     }
193     codeInfo_.push_back({addr, size});
194     if (curSec.isValidAOTSec()) {
195         secInfos_[curSec.GetIntIndex()] = std::make_pair(addr, size);
196     }
197     return addr;
198 }
199 
AllocaCodeSection(uintptr_t size,const char * sectionName)200 uint8_t *CodeInfo::AllocaCodeSection(uintptr_t size, const char *sectionName)
201 {
202     return AllocaCodeSectionImp(size, sectionName, &CodeInfo::AllocaInReqSecBuffer);
203 }
204 
AllocaCodeSectionOnDemand(uintptr_t size,const char * sectionName)205 uint8_t *CodeInfo::AllocaCodeSectionOnDemand(uintptr_t size, const char *sectionName)
206 {
207     return AllocaCodeSectionImp(size, sectionName, &CodeInfo::AllocaOnDemand);
208 }
209 
AllocaDataSectionImp(uintptr_t size,const char * sectionName,AllocaSectionCallback allocaInReqSecBuffer,AllocaSectionCallback allocaInNotReqSecBuffer)210 uint8_t *CodeInfo::AllocaDataSectionImp(uintptr_t size, const char *sectionName,
211                                         AllocaSectionCallback allocaInReqSecBuffer,
212                                         AllocaSectionCallback allocaInNotReqSecBuffer)
213 {
214     uint8_t *addr = nullptr;
215     auto curSec = ElfSection(sectionName);
216     // rodata section needs 16 bytes alignment
217     if (curSec.InRodataSection()) {
218         size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_REGION));
219         if (!alreadyPageAlign_) {
220             addr = curSec.isSequentialAOTSec() ? (this->*allocaInReqSecBuffer)(size, AOTFileInfo::PAGE_ALIGN)
221                                                : (this->*allocaInNotReqSecBuffer)(size, AOTFileInfo::PAGE_ALIGN);
222             alreadyPageAlign_ = true;
223         } else {
224             addr = curSec.isSequentialAOTSec() ? (this->*allocaInReqSecBuffer)(size, AOTFileInfo::DATA_SEC_ALIGN)
225                                                : (this->*allocaInNotReqSecBuffer)(size, AOTFileInfo::DATA_SEC_ALIGN);
226         }
227     } else {
228         addr = curSec.isSequentialAOTSec() ? (this->*allocaInReqSecBuffer)(size, 0)
229                                            : (this->*allocaInNotReqSecBuffer)(size, 0);
230     }
231     if (curSec.isValidAOTSec()) {
232         secInfos_[curSec.GetIntIndex()] = std::make_pair(addr, size);
233     }
234     return addr;
235 
236 }
237 
AllocaDataSection(uintptr_t size,const char * sectionName)238 uint8_t *CodeInfo::AllocaDataSection(uintptr_t size, const char *sectionName)
239 {
240     return AllocaDataSectionImp(size, sectionName, &CodeInfo::AllocaInReqSecBuffer, &CodeInfo::AllocaInNotReqSecBuffer);
241 }
242 
AllocaDataSectionOnDemand(uintptr_t size,const char * sectionName)243 uint8_t *CodeInfo::AllocaDataSectionOnDemand(uintptr_t size, const char *sectionName)
244 {
245     return AllocaDataSectionImp(size, sectionName, &CodeInfo::AllocaOnDemand, &CodeInfo::AllocaOnDemand);
246 }
247 
SaveFunc2Addr(std::string funcName,uint32_t address)248 void CodeInfo::SaveFunc2Addr(std::string funcName, uint32_t address)
249 {
250     auto itr = func2FuncInfo.find(funcName);
251     if (itr != func2FuncInfo.end()) {
252         itr->second.addr = address;
253         return;
254     }
255     func2FuncInfo.insert(
256         std::pair<std::string, FuncInfo>(funcName, {address, 0, kungfu::CalleeRegAndOffsetVec()}));
257 }
258 
SaveFunc2FPtoPrevSPDelta(std::string funcName,int32_t fp2PrevSpDelta)259 void CodeInfo::SaveFunc2FPtoPrevSPDelta(std::string funcName, int32_t fp2PrevSpDelta)
260 {
261     auto itr = func2FuncInfo.find(funcName);
262     if (itr != func2FuncInfo.end()) {
263         itr->second.fp2PrevFrameSpDelta = fp2PrevSpDelta;
264         return;
265     }
266     func2FuncInfo.insert(
267         std::pair<std::string, FuncInfo>(funcName, {0, fp2PrevSpDelta, kungfu::CalleeRegAndOffsetVec()}));
268 }
269 
SaveFunc2CalleeOffsetInfo(std::string funcName,kungfu::CalleeRegAndOffsetVec calleeRegInfo)270 void CodeInfo::SaveFunc2CalleeOffsetInfo(std::string funcName, kungfu::CalleeRegAndOffsetVec calleeRegInfo)
271 {
272     auto itr = func2FuncInfo.find(funcName);
273     if (itr != func2FuncInfo.end()) {
274         itr->second.calleeRegInfo = calleeRegInfo;
275         return;
276     }
277     func2FuncInfo.insert(
278         std::pair<std::string, FuncInfo>(funcName, {0, 0, calleeRegInfo}));
279 }
280 
SavePC2DeoptInfo(uint64_t pc,std::vector<uint8_t> deoptInfo)281 void CodeInfo::SavePC2DeoptInfo(uint64_t pc, std::vector<uint8_t> deoptInfo)
282 {
283     pc2DeoptInfo.insert(std::pair<uint64_t, std::vector<uint8_t>>(pc, deoptInfo));
284 }
285 
SavePC2CallSiteInfo(uint64_t pc,std::vector<uint8_t> callSiteInfo)286 void CodeInfo::SavePC2CallSiteInfo(uint64_t pc, std::vector<uint8_t> callSiteInfo)
287 {
288     pc2CallsiteInfo.insert(std::pair<uint64_t, std::vector<uint8_t>>(pc, callSiteInfo));
289 }
290 
GetFuncInfos() const291 const std::map<std::string, CodeInfo::FuncInfo> &CodeInfo::GetFuncInfos() const
292 {
293     return func2FuncInfo;
294 }
295 
GetPC2DeoptInfo() const296 const std::map<uint64_t, std::vector<uint8_t>> &CodeInfo::GetPC2DeoptInfo() const
297 {
298     return pc2DeoptInfo;
299 }
300 
GetPC2CallsiteInfo() const301 const std::unordered_map<uint64_t, std::vector<uint8_t>> &CodeInfo::GetPC2CallsiteInfo() const
302 {
303     return pc2CallsiteInfo;
304 }
305 
Reset()306 void CodeInfo::Reset()
307 {
308     codeInfo_.clear();
309 }
310 
GetSectionAddr(ElfSecName sec) const311 uint8_t *CodeInfo::GetSectionAddr(ElfSecName sec) const
312 {
313     auto curSection = ElfSection(sec);
314     auto idx = curSection.GetIntIndex();
315     return const_cast<uint8_t *>(secInfos_[idx].first);
316 }
317 
GetSectionSize(ElfSecName sec) const318 size_t CodeInfo::GetSectionSize(ElfSecName sec) const
319 {
320     auto curSection = ElfSection(sec);
321     auto idx = curSection.GetIntIndex();
322     return secInfos_[idx].second;
323 }
324 
GetCodeInfo() const325 std::vector<std::pair<uint8_t *, uintptr_t>> CodeInfo::GetCodeInfo() const
326 {
327     return codeInfo_;
328 }
329 
GenerateCodeForStub(Circuit * circuit,const ControlFlowGraph & graph,size_t index,const CompilationConfig * cfg)330 void LLVMIRGeneratorImpl::GenerateCodeForStub(Circuit *circuit, const ControlFlowGraph &graph, size_t index,
331                                               const CompilationConfig *cfg)
332 {
333     LLVMValueRef function = module_->GetFunction(index);
334     const CallSignature* cs = module_->GetCSign(index);
335     LLVMIRBuilder builder(&graph, circuit, module_, function, cfg, cs->GetCallConv(), enableLog_, false, cs->GetName());
336     builder.Build();
337 }
338 
GenerateCode(Circuit * circuit,const ControlFlowGraph & graph,const CompilationConfig * cfg,const panda::ecmascript::MethodLiteral * methodLiteral,const JSPandaFile * jsPandaFile,const std::string & methodName,const FrameType frameType,bool enableOptInlining,bool enableOptBranchProfiling)339 void LLVMIRGeneratorImpl::GenerateCode(Circuit *circuit, const ControlFlowGraph &graph, const CompilationConfig *cfg,
340                                        const panda::ecmascript::MethodLiteral *methodLiteral,
341                                        const JSPandaFile *jsPandaFile, const std::string &methodName,
342                                        const FrameType frameType, bool enableOptInlining, bool enableOptBranchProfiling)
343 {
344     auto function = module_->AddFunc(methodLiteral, jsPandaFile);
345     circuit->SetFrameType(frameType);
346     CallSignature::CallConv conv;
347     if (methodLiteral->IsFastCall()) {
348         conv = CallSignature::CallConv::CCallConv;
349     } else {
350         conv = CallSignature::CallConv::WebKitJSCallConv;
351     }
352     LLVMIRBuilder builder(&graph, circuit, module_, function, cfg, conv,
353                           enableLog_, methodLiteral->IsFastCall(), methodName,
354                           enableOptInlining, enableOptBranchProfiling);
355     builder.Build();
356 }
357 
RoundTripAllocateCodeSection(void * object,uintptr_t size,unsigned alignment,unsigned sectionID,const char * sectionName)358 static uint8_t *RoundTripAllocateCodeSection(void *object, uintptr_t size, [[maybe_unused]] unsigned alignment,
359                                              [[maybe_unused]] unsigned sectionID, const char *sectionName)
360 {
361     struct CodeInfo& state = *static_cast<struct CodeInfo*>(object);
362     return state.AllocaCodeSection(size, sectionName);
363 }
364 
RoundTripAllocateCodeSectionOnDemand(void * object,uintptr_t size,unsigned alignment,unsigned sectionID,const char * sectionName)365 static uint8_t *RoundTripAllocateCodeSectionOnDemand(void *object, uintptr_t size, [[maybe_unused]] unsigned alignment,
366                                                      [[maybe_unused]] unsigned sectionID, const char *sectionName)
367 {
368     struct CodeInfo& state = *static_cast<struct CodeInfo*>(object);
369     return state.AllocaCodeSectionOnDemand(size, sectionName);
370 }
371 
RoundTripAllocateDataSection(void * object,uintptr_t size,unsigned alignment,unsigned sectionID,const char * sectionName,LLVMBool isReadOnly)372 static uint8_t *RoundTripAllocateDataSection(void *object, uintptr_t size, [[maybe_unused]] unsigned alignment,
373                                              [[maybe_unused]] unsigned sectionID, const char *sectionName,
374                                              [[maybe_unused]] LLVMBool isReadOnly)
375 {
376     struct CodeInfo& state = *static_cast<struct CodeInfo*>(object);
377     return state.AllocaDataSection(size, sectionName);
378 }
379 
RoundTripAllocateDataSectionOnDemand(void * object,uintptr_t size,unsigned alignment,unsigned sectionID,const char * sectionName,LLVMBool isReadOnly)380 static uint8_t *RoundTripAllocateDataSectionOnDemand(void *object, uintptr_t size, [[maybe_unused]] unsigned alignment,
381                                                      [[maybe_unused]] unsigned sectionID, const char *sectionName,
382                                                      [[maybe_unused]] LLVMBool isReadOnly)
383 {
384     struct CodeInfo& state = *static_cast<struct CodeInfo*>(object);
385     return state.AllocaDataSectionOnDemand(size, sectionName);
386 }
387 
RoundTripFinalizeMemory(void * object,char ** errMsg)388 static LLVMBool RoundTripFinalizeMemory([[maybe_unused]] void *object, [[maybe_unused]] char **errMsg)
389 {
390     return 0;
391 }
392 
RoundTripDestroy(void * object)393 static void RoundTripDestroy([[maybe_unused]] void *object)
394 {
395     return;
396 }
397 
UseRoundTripSectionMemoryManager(bool isJit)398 void LLVMAssembler::UseRoundTripSectionMemoryManager(bool isJit)
399 {
400     auto sectionMemoryManager = std::make_unique<llvm::SectionMemoryManager>();
401     options_.MCJMM = LLVMCreateSimpleMCJITMemoryManager(
402         &codeInfo_, isJit ? RoundTripAllocateCodeSectionOnDemand : RoundTripAllocateCodeSection,
403         isJit ? RoundTripAllocateDataSectionOnDemand : RoundTripAllocateDataSection, RoundTripFinalizeMemory,
404         RoundTripDestroy);
405 }
406 
BuildMCJITEngine()407 bool LLVMAssembler::BuildMCJITEngine()
408 {
409     LLVMBool ret = LLVMCreateMCJITCompilerForModule(&engine_, module_, &options_, sizeof(options_), &error_);
410     if (ret) {
411         LOG_COMPILER(FATAL) << "error_ : " << error_;
412         return false;
413     }
414     llvm::unwrap(engine_)->RegisterJITEventListener(&listener_);
415     return true;
416 }
417 
BuildAndRunPasses()418 void LLVMAssembler::BuildAndRunPasses()
419 {
420     LLVMPassManagerBuilderRef pmBuilder = LLVMPassManagerBuilderCreate();
421     LLVMPassManagerBuilderSetOptLevel(pmBuilder, options_.OptLevel); // using O3 optimization level
422     LLVMPassManagerBuilderSetSizeLevel(pmBuilder, 0);
423     LLVMPassManagerBuilderSetDisableUnrollLoops(pmBuilder, 0);
424 
425     // pass manager creation:rs4gc pass is the only pass in modPass, other opt module-based pass are in modPass1
426     LLVMPassManagerRef funcPass = LLVMCreateFunctionPassManagerForModule(module_);
427     LLVMPassManagerRef modPass = LLVMCreatePassManager();
428     LLVMPassManagerRef modPass1 = LLVMCreatePassManager();
429 
430     // add pass into pass managers
431     LLVMPassManagerBuilderPopulateFunctionPassManager(pmBuilder, funcPass);
432     llvm::unwrap(modPass)->add(LLVMCreateRewriteStatepointsForGCLegacyPass()); // rs4gc pass added
433     LLVMPassManagerBuilderPopulateModulePassManager(pmBuilder, modPass1);
434 
435     LLVMRunPassManager(modPass, module_);
436     LLVMInitializeFunctionPassManager(funcPass);
437     for (LLVMValueRef fn = LLVMGetFirstFunction(module_); fn; fn = LLVMGetNextFunction(fn)) {
438         LLVMRunFunctionPassManager(funcPass, fn);
439     }
440     LLVMFinalizeFunctionPassManager(funcPass);
441     LLVMRunPassManager(modPass1, module_);
442 
443     LLVMPassManagerBuilderDispose(pmBuilder);
444     LLVMDisposePassManager(funcPass);
445     LLVMDisposePassManager(modPass);
446     LLVMDisposePassManager(modPass1);
447 }
448 
BuildAndRunPassesFastMode()449 void LLVMAssembler::BuildAndRunPassesFastMode()
450 {
451     LLVMPassManagerBuilderRef pmBuilder = LLVMPassManagerBuilderCreate();
452     LLVMPassManagerBuilderSetOptLevel(pmBuilder, options_.OptLevel); // using O3 optimization level
453     LLVMPassManagerBuilderSetSizeLevel(pmBuilder, 0);
454 
455     // pass manager creation:rs4gc pass is the only pass in modPass, other opt module-based pass are in modPass1
456     LLVMPassManagerRef funcPass = LLVMCreateFunctionPassManagerForModule(module_);
457     LLVMPassManagerRef modPass = LLVMCreatePassManager();
458 
459     // add pass into pass managers
460     LLVMPassManagerBuilderPopulateFunctionPassManager(pmBuilder, funcPass);
461     llvm::unwrap(modPass)->add(LLVMCreateRewriteStatepointsForGCLegacyPass()); // rs4gc pass added
462 
463     LLVMInitializeFunctionPassManager(funcPass);
464     for (LLVMValueRef fn = LLVMGetFirstFunction(module_); fn; fn = LLVMGetNextFunction(fn)) {
465         LLVMRunFunctionPassManager(funcPass, fn);
466     }
467     LLVMFinalizeFunctionPassManager(funcPass);
468     LLVMRunPassManager(modPass, module_);
469 
470     LLVMPassManagerBuilderDispose(pmBuilder);
471     LLVMDisposePassManager(funcPass);
472     LLVMDisposePassManager(modPass);
473 }
474 
LLVMAssembler(LLVMModule * lm,CodeInfo::CodeSpaceOnDemand & codeSpaceOnDemand,LOptions option)475 LLVMAssembler::LLVMAssembler(LLVMModule *lm, CodeInfo::CodeSpaceOnDemand &codeSpaceOnDemand, LOptions option)
476     : Assembler(codeSpaceOnDemand),
477       llvmModule_(lm),
478       module_(llvmModule_->GetModule()),
479       listener_(this)
480 {
481     Initialize(option);
482 }
483 
~LLVMAssembler()484 LLVMAssembler::~LLVMAssembler()
485 {
486     if (engine_ != nullptr) {
487         if (module_ != nullptr) {
488             char *error = nullptr;
489             LLVMRemoveModule(engine_, module_, &module_, &error);
490             if (error != nullptr) {
491                 LLVMDisposeMessage(error);
492             }
493         }
494         LLVMDisposeExecutionEngine(engine_);
495         engine_ = nullptr;
496     }
497     module_ = nullptr;
498     error_ = nullptr;
499 }
500 
Run(const CompilerLog & log,bool fastCompileMode,bool isJit)501 void LLVMAssembler::Run(const CompilerLog &log, bool fastCompileMode, [[maybe_unused]]bool isJit)
502 {
503     char *error = nullptr;
504     std::string originName = llvm::unwrap(module_)->getModuleIdentifier() + ".ll";
505     std::string optName = llvm::unwrap(module_)->getModuleIdentifier() + "_opt.ll";
506     if (log.OutputLLIR()) {
507         LLVMPrintModuleToFile(module_, originName.c_str(), &error);
508         std::string errInfo = (error != nullptr) ? error : "";
509         LOG_COMPILER(INFO) << "generate " << originName << " " << errInfo;
510     }
511     LLVMVerifyModule(module_, LLVMAbortProcessAction, &error);
512     LLVMDisposeMessage(error);
513     UseRoundTripSectionMemoryManager(isJit);
514     if (!BuildMCJITEngine()) {
515         return;
516     }
517     llvm::unwrap(engine_)->setProcessAllSections(true);
518     if (fastCompileMode) {
519         BuildAndRunPassesFastMode();
520     } else {
521         BuildAndRunPasses();
522     }
523     if (log.OutputLLIR()) {
524         error = nullptr;
525         LLVMPrintModuleToFile(module_, optName.c_str(), &error);
526         std::string errInfo = (error != nullptr) ? error : "";
527         LOG_COMPILER(INFO) << "generate " << optName << " " << errInfo;
528     }
529 }
530 
Initialize(LOptions option)531 void LLVMAssembler::Initialize(LOptions option)
532 {
533     std::string triple(LLVMGetTarget(module_));
534     if (triple.compare(TARGET_X64) == 0) {
535 #if defined(PANDA_TARGET_MACOS) || !defined(PANDA_TARGET_ARM64)
536         LLVMInitializeX86TargetInfo();
537         LLVMInitializeX86TargetMC();
538         LLVMInitializeX86Disassembler();
539         /* this method must be called, ohterwise "Target does not support MC emission" */
540         LLVMInitializeX86AsmPrinter();
541         LLVMInitializeX86AsmParser();
542         LLVMInitializeX86Target();
543 #endif
544     } else if (triple.compare(TARGET_AARCH64) == 0) {
545         LLVMInitializeAArch64TargetInfo();
546         LLVMInitializeAArch64TargetMC();
547         LLVMInitializeAArch64Disassembler();
548         LLVMInitializeAArch64AsmPrinter();
549         LLVMInitializeAArch64AsmParser();
550         LLVMInitializeAArch64Target();
551     } else {
552         LOG_ECMA(FATAL) << "this branch is unreachable";
553         UNREACHABLE();
554     }
555 
556     LLVMLinkAllBuiltinGCs();
557     LLVMInitializeMCJITCompilerOptions(&options_, sizeof(options_));
558     options_.OptLevel = option.optLevel;
559     // NOTE: Just ensure that this field still exists for PIC option
560     options_.RelMode = static_cast<LLVMRelocMode>(option.relocMode);
561     options_.NoFramePointerElim = static_cast<int32_t>(option.genFp);
562     options_.CodeModel = LLVMCodeModelSmall;
563 }
564 
SymbolLookupCallback(void * disInfo,uint64_t referenceValue,uint64_t * referenceType,uint64_t referencePC,const char ** referenceName)565 static const char *SymbolLookupCallback([[maybe_unused]] void *disInfo, [[maybe_unused]] uint64_t referenceValue,
566                                         uint64_t *referenceType, [[maybe_unused]] uint64_t referencePC,
567                                         [[maybe_unused]] const char **referenceName)
568 {
569     *referenceType = LLVMDisassembler_ReferenceType_InOut_None;
570     return nullptr;
571 }
572 
GetCalleeReg2Offset(LLVMValueRef fn,const CompilerLog & log)573 kungfu::CalleeRegAndOffsetVec LLVMAssembler::GetCalleeReg2Offset(LLVMValueRef fn, const CompilerLog &log)
574 {
575     kungfu::CalleeRegAndOffsetVec info;
576     llvm::Function* func = llvm::unwrap<llvm::Function>(fn);
577     ASSERT(func != nullptr);
578 #if defined(PANDA_TARGET_MACOS)
579     for (const auto &Attr : func->getAttributes().getFnAttributes()) {
580 #else
581     for (const auto &Attr : func->getAttributes().getFnAttrs()) {
582 #endif
583         if (Attr.isStringAttribute()) {
584             std::string str = std::string(Attr.getKindAsString().data());
585             std::string expectedKey = "DwarfReg";
586             size_t keySZ = expectedKey.size();
587             size_t strSZ = str.size();
588             if (strSZ >= keySZ && str.substr(0, keySZ) == expectedKey) {
589                 int RegNum = std::stoi(str.substr(keySZ, strSZ - keySZ));
590                 auto value = std::stoi(std::string(Attr.getValueAsString()));
591                 info.push_back(std::make_pair(RegNum, value));
592                 (void)log;
593             }
594         }
595     }
596     return info;
597 }
598 
599 int LLVMAssembler::GetFpDeltaPrevFramSp(LLVMValueRef fn, const CompilerLog &log)
600 {
601     int fpToCallerSpDelta = 0;
602     const char attrKey[] = "fpToCallerSpDelta"; // this key must consistent with llvm backend.
603     LLVMAttributeRef attrirbuteRef = LLVMGetStringAttributeAtIndex(fn, llvm::AttributeList::FunctionIndex,
604                                                                    attrKey, strlen(attrKey));
605     if (attrirbuteRef) {
606         llvm::Attribute attr = llvm::unwrap(attrirbuteRef);
607         auto value = attr.getValueAsString().data();
608         fpToCallerSpDelta = atoi(value);
609         if (log.AllMethod()) {
610             size_t length;
611             LOG_COMPILER(DEBUG) << " funcName: " << LLVMGetValueName2(fn, &length) << " fpToCallerSpDelta:"
612             << fpToCallerSpDelta;
613         }
614     }
615     return fpToCallerSpDelta;
616 }
617 
618 static uint32_t GetInstrValue(size_t instrSize, uint8_t *instrAddr)
619 {
620     uint32_t value = 0;
621     if (instrSize <= sizeof(uint32_t)) {
622         if (memcpy_s(&value, sizeof(uint32_t), instrAddr, instrSize) != EOK) {
623             LOG_FULL(FATAL) << "memcpy_s failed";
624             UNREACHABLE();
625         }
626     }
627     return value;
628 }
629 
630 void LLVMAssembler::PrintInstAndStep(uint64_t &instrOffset, uint8_t **instrAddr, uintptr_t &numBytes,
631                                      size_t instSize, uint64_t textOffset, char *outString,
632                                      std::ostringstream &codeStream, bool logFlag)
633 {
634     if (instSize == 0) {
635         instSize = 4; // 4: default instruction step size while instruction can't be resolved or be constant
636     }
637     if (logFlag) {
638         uint64_t unitedInstOffset = instrOffset + textOffset;
639         // 8: length of output content
640         codeStream << std::setw(8) << std::setfill('0') << std::hex << unitedInstOffset << ":" << std::setw(8)
641                            << GetInstrValue(instSize, *instrAddr) << " " << outString << std::endl;
642     }
643     instrOffset += instSize;
644     *instrAddr += instSize;
645     numBytes -= instSize;
646 }
647 
648 void LLVMAssembler::Disassemble(const std::map<uintptr_t, std::string> *addr2name,
649                                 const std::string& triple, uint8_t *buf, size_t size)
650 {
651     LLVMModuleRef module = LLVMModuleCreateWithName("Emit");
652     LLVMSetTarget(module, triple.c_str());
653     LLVMDisasmContextRef ctx = LLVMCreateDisasm(LLVMGetTarget(module), nullptr, 0, nullptr, SymbolLookupCallback);
654     if (!ctx) {
655         LOG_COMPILER(ERROR) << "ERROR: Couldn't create disassembler for triple!";
656         return;
657     }
658     uint8_t *instrAddr = buf;
659     uint64_t bufAddr = reinterpret_cast<uint64_t>(buf);
660     size_t numBytes = size;
661     uint64_t instrOffset = 0;
662     const size_t outStringSize = 256;
663     char outString[outStringSize];
664     std::ostringstream codeStream;
665     while (numBytes > 0) {
666         uint64_t addr = reinterpret_cast<uint64_t>(instrAddr) - bufAddr;
667         if (addr2name != nullptr && addr2name->find(addr) != addr2name->end()) {
668             std::string methodName = addr2name->at(addr);
669             codeStream << "------------------- asm code [" << methodName << "] -------------------"
670                        << std::endl;
671         }
672         size_t instSize = LLVMDisasmInstruction(ctx, instrAddr, numBytes, instrOffset, outString, outStringSize);
673         PrintInstAndStep(instrOffset, &instrAddr, numBytes, instSize, 0, outString, codeStream);
674     }
675     LOG_ECMA(INFO) << "\n" << codeStream.str();
676     LLVMDisasmDispose(ctx);
677 }
678 
679 static void DecodeDebugInfo(uint64_t addr, uint64_t secIndex, char* outString, size_t outStringSize,
680                             DWARFContext *ctx, LLVMModule* module, const std::string &funcName)
681 {
682     object::SectionedAddress secAddr = {addr, secIndex};
683     DILineInfoSpecifier spec;
684     spec.FNKind = DINameKind::ShortName;
685 
686     DILineInfo info = ctx->getLineInfoForAddress(secAddr, spec);
687     if (info && info.Line > 0) {
688         std::string debugInfo = "\t\t;";
689         debugInfo += module->GetDebugInfo()->GetComment(funcName, info.Line - 1);
690         size_t len = strlen(outString);
691         if (len + debugInfo.size() < outStringSize) {
692             if (strcpy_s(outString + len, outStringSize - len, debugInfo.c_str()) != EOK) {
693                 LOG_FULL(FATAL) << "strcpy_s failed";
694                 UNREACHABLE();
695             }
696         }
697     }
698 }
699 
700 uint64_t LLVMAssembler::GetTextSectionIndex() const
701 {
702     uint64_t index = 0;
703     for (object::section_iterator it = objFile_->section_begin(); it != objFile_->section_end(); ++it) {
704         auto name = it->getName();
705         if (name) {
706             std::string str = name->str();
707             if (str == ".text") {
708                 index = it->getIndex();
709                 ASSERT(it->isText());
710                 break;
711             }
712         }
713     }
714     return index;
715 }
716 
717 void LLVMAssembler::Disassemble(const std::map<uintptr_t, std::string> &addr2name, uint64_t textOffset,
718                                 const CompilerLog &log, const MethodLogList &logList,
719                                 std::ostringstream &codeStream) const
720 {
721     const uint64_t textSecIndex = GetTextSectionIndex();
722     LLVMDisasmContextRef disCtx = LLVMCreateDisasm(LLVMGetTarget(module_), nullptr, 0, nullptr, SymbolLookupCallback);
723     bool logFlag = false;
724     std::unique_ptr<DWARFContext> dwarfCtx = DWARFContext::create(*objFile_);
725 
726     for (auto it : codeInfo_.GetCodeInfo()) {
727         uint8_t *instrAddr = it.first;
728         size_t numBytes = it.second;
729         uint64_t instrOffset = 0;
730 
731         const size_t outStringSize = 512;
732         char outString[outStringSize] = {'\0'};
733         std::string methodName;
734 
735         while (numBytes > 0) {
736             uint64_t addr = reinterpret_cast<uint64_t>(instrAddr);
737             if (addr2name.find(addr) != addr2name.end()) {
738                 methodName = addr2name.at(addr);
739                 logFlag = log.OutputASM();
740                 if (log.CertainMethod()) {
741                     logFlag = logFlag && logList.IncludesMethod(methodName);
742                 } else if (log.NoneMethod()) {
743                     logFlag = false;
744                 }
745                 if (logFlag) {
746                     codeStream << "------------------- asm code [" << methodName << "] -------------------"
747                                << std::endl;
748                 }
749             }
750 
751             size_t instSize = LLVMDisasmInstruction(disCtx, instrAddr, numBytes, instrOffset, outString, outStringSize);
752             DecodeDebugInfo(instrOffset, textSecIndex, outString, outStringSize,
753                             dwarfCtx.get(), llvmModule_, methodName);
754             PrintInstAndStep(instrOffset, &instrAddr, numBytes, instSize, textOffset, outString, codeStream, logFlag);
755         }
756     }
757     LLVMDisasmDispose(disCtx);
758 }
759 }  // namespace panda::ecmascript::kungfu
760