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 §ion : 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