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 67namespace panda::ecmascript::kungfu { 68using namespace panda::ecmascript; 69using namespace llvm; 70 71CodeInfo::CodeInfo(CodeSpaceOnDemand &codeSpaceOnDemand) : codeSpaceOnDemand_(codeSpaceOnDemand) 72{ 73 secInfos_.fill(std::make_pair(nullptr, 0)); 74} 75 76CodeInfo::~CodeInfo() 77{ 78 Reset(); 79} 80 81CodeInfo::CodeSpace *CodeInfo::CodeSpace::GetInstance() 82{ 83 static CodeSpace *codeSpace = new CodeSpace(); 84 return codeSpace; 85} 86 87CodeInfo::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 101CodeInfo::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 115uint8_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 134uint8_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 152CodeInfo::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 163uint8_t *CodeInfo::AllocaOnDemand(uintptr_t size, size_t alignSize) 164{ 165 return codeSpaceOnDemand_.Alloca(size, true, alignSize); 166} 167 168uint8_t *CodeInfo::AllocaInReqSecBuffer(uintptr_t size, size_t alignSize) 169{ 170 return CodeSpace::GetInstance()->Alloca(size, true, alignSize); 171} 172 173uint8_t *CodeInfo::AllocaInNotReqSecBuffer(uintptr_t size, size_t alignSize) 174{ 175 return CodeSpace::GetInstance()->Alloca(size, false, alignSize); 176} 177 178uint8_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 200uint8_t *CodeInfo::AllocaCodeSection(uintptr_t size, const char *sectionName) 201{ 202 return AllocaCodeSectionImp(size, sectionName, &CodeInfo::AllocaInReqSecBuffer); 203} 204 205uint8_t *CodeInfo::AllocaCodeSectionOnDemand(uintptr_t size, const char *sectionName) 206{ 207 return AllocaCodeSectionImp(size, sectionName, &CodeInfo::AllocaOnDemand); 208} 209 210uint8_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 238uint8_t *CodeInfo::AllocaDataSection(uintptr_t size, const char *sectionName) 239{ 240 return AllocaDataSectionImp(size, sectionName, &CodeInfo::AllocaInReqSecBuffer, &CodeInfo::AllocaInNotReqSecBuffer); 241} 242 243uint8_t *CodeInfo::AllocaDataSectionOnDemand(uintptr_t size, const char *sectionName) 244{ 245 return AllocaDataSectionImp(size, sectionName, &CodeInfo::AllocaOnDemand, &CodeInfo::AllocaOnDemand); 246} 247 248void 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 259void 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 270void 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 281void 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 286void 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 291const std::map<std::string, CodeInfo::FuncInfo> &CodeInfo::GetFuncInfos() const 292{ 293 return func2FuncInfo; 294} 295 296const std::map<uint64_t, std::vector<uint8_t>> &CodeInfo::GetPC2DeoptInfo() const 297{ 298 return pc2DeoptInfo; 299} 300 301const std::unordered_map<uint64_t, std::vector<uint8_t>> &CodeInfo::GetPC2CallsiteInfo() const 302{ 303 return pc2CallsiteInfo; 304} 305 306void CodeInfo::Reset() 307{ 308 codeInfo_.clear(); 309} 310 311uint8_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 318size_t CodeInfo::GetSectionSize(ElfSecName sec) const 319{ 320 auto curSection = ElfSection(sec); 321 auto idx = curSection.GetIntIndex(); 322 return secInfos_[idx].second; 323} 324 325std::vector<std::pair<uint8_t *, uintptr_t>> CodeInfo::GetCodeInfo() const 326{ 327 return codeInfo_; 328} 329 330void 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 339void 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 358static 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 365static 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 372static 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 380static 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 388static LLVMBool RoundTripFinalizeMemory([[maybe_unused]] void *object, [[maybe_unused]] char **errMsg) 389{ 390 return 0; 391} 392 393static void RoundTripDestroy([[maybe_unused]] void *object) 394{ 395 return; 396} 397 398void 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 407bool 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 418void 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 449void 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 475LLVMAssembler::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 484LLVMAssembler::~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 501void LLVMAssembler::Run(const CompilerLog &log, bool fastCompileMode, 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 531void 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 565static 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 573kungfu::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 599int 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 618static 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 630void 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 648void 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 679static 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 700uint64_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 717void 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