1/* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "ecmascript/compiler/file_generators.h" 17 18#include "ecmascript/common.h" 19#include "ecmascript/compiler/aot_file/aot_file_manager.h" 20#include "ecmascript/compiler/pgo_type/pgo_type_manager.h" 21#include "ecmascript/pgo_profiler/pgo_profiler_manager.h" 22#include "ecmascript/platform/code_sign.h" 23#include "ecmascript/platform/directory.h" 24#include "ecmascript/platform/os.h" 25#include "ecmascript/snapshot/mem/snapshot.h" 26#include "ecmascript/stackmap/ark_stackmap_builder.h" 27#include "ecmascript/stackmap/llvm/llvm_stackmap_parser.h" 28#ifdef COMPILE_MAPLE 29#include "ecmascript/compiler/codegen/maple/litecg_codegen.h" 30#include "ecmascript/compiler/codegen/maple/litecg_ir_builder.h" 31#include "ecmascript/compiler/codegen/maple/maple_be/include/litecg/litecg.h" 32#include "ecmascript/stackmap/litecg/litecg_stackmap_type.h" 33#ifdef JIT_ENABLE_CODE_SIGN 34#include "ecmascript/compiler/jit_signcode.h" 35#endif 36#endif 37#include "ecmascript/jit/jit.h" 38#include "ecmascript/jit/jit_task.h" 39#include "ecmascript/compiler/jit_compiler.h" 40 41namespace panda::ecmascript::kungfu { 42void Module::CollectStackMapDes(ModuleSectionDes& des) const 43{ 44 uint32_t stackmapSize = des.GetSecSize(ElfSecName::LLVM_STACKMAP); 45 std::unique_ptr<uint8_t[]> stackmapPtr(std::make_unique<uint8_t[]>(stackmapSize)); 46 uint64_t addr = des.GetSecAddr(ElfSecName::LLVM_STACKMAP); 47 if (addr == 0) { // assembler stub don't existed llvm stackmap 48 return; 49 } 50 uint64_t textAddr = des.GetSecAddr(ElfSecName::TEXT); 51 if (memcpy_s(stackmapPtr.get(), stackmapSize, reinterpret_cast<void *>(addr), stackmapSize) != EOK) { 52 LOG_COMPILER(FATAL) << "memcpy_s failed"; 53 UNREACHABLE(); 54 } 55 std::shared_ptr<uint8_t> ptr = nullptr; 56 uint32_t size = 0; 57 ArkStackMapBuilder builder; 58 std::tie(ptr, size) = builder.Run(std::move(stackmapPtr), textAddr, irModule_->GetTriple()); 59 des.EraseSec(ElfSecName::LLVM_STACKMAP); 60 des.SetArkStackMapPtr(ptr); 61 des.SetArkStackMapSize(size); 62} 63 64void Module::CollectAnStackMapDes(ModuleSectionDes& des, uint64_t textOffset, 65 CGStackMapInfo &stackMapInfo) const 66{ 67#ifdef COMPILE_MAPLE 68 if (!IsLLVM()) { 69 static_cast<LiteCGAssembler*>(assembler_)->CollectAnStackMap(stackMapInfo); 70 return; 71 } 72#endif 73 uint32_t stackmapSize = des.GetSecSize(ElfSecName::LLVM_STACKMAP); 74 std::unique_ptr<uint8_t[]> stackmapPtr(std::make_unique<uint8_t[]>(stackmapSize)); 75 uint64_t addr = des.GetSecAddr(ElfSecName::LLVM_STACKMAP); 76 if (addr == 0) { // assembler stub don't existed llvm stackmap 77 return; 78 } 79 uint64_t textAddr = des.GetSecAddr(ElfSecName::TEXT); 80 if (memcpy_s(stackmapPtr.get(), stackmapSize, reinterpret_cast<void *>(addr), stackmapSize) != EOK) { 81 LOG_COMPILER(FATAL) << "memcpy_s failed"; 82 UNREACHABLE(); 83 } 84 ArkStackMapBuilder builder; 85 builder.Collect(std::move(stackmapPtr), textAddr, textOffset, stackMapInfo); 86 des.EraseSec(ElfSecName::LLVM_STACKMAP); 87} 88 89std::vector<uintptr_t> Module::GetFuncEntryPoints() 90{ 91 std::vector<uintptr_t> entrys; 92 if (irModule_->GetModuleKind() != MODULE_LLVM) { 93 std::cout << "GetFuncEntryPoints is not supported for litecg currently" << std::endl; 94 return entrys; 95 } 96 LLVMModule *llvmModule = static_cast<LLVMModule *>(irModule_); 97 LLVMAssembler *assembler = static_cast<LLVMAssembler *>(assembler_); 98 auto engine = assembler->GetEngine(); 99 100 for (size_t j = 0; j < llvmModule->GetFuncCount(); j++) { 101 LLVMValueRef func = llvmModule->GetFunction(j); 102 ASSERT(func != nullptr); 103 uintptr_t entry = reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(engine, func)); 104 entrys.push_back(entry); 105 } 106 return entrys; 107} 108 109void Module::CollectFuncEntryInfo(const std::vector<uintptr_t>& entrys, std::map<uintptr_t, std::string> &addr2name, 110 StubFileInfo &stubInfo, uint32_t moduleIndex, const CompilerLog &log) 111{ 112 LLVMModule *llvmModule = static_cast<LLVMModule*>(irModule_); 113 LLVMAssembler *assembler = static_cast<LLVMAssembler*>(assembler_); 114 auto codeBuff = assembler->GetSectionAddr(ElfSecName::TEXT); 115 auto callSigns = llvmModule->GetCSigns(); 116 const size_t funcCount = entrys.size(); 117 funcCount_ = funcCount; 118 startIndex_ = stubInfo.GetEntrySize(); 119 120 for (size_t j = 0; j < funcCount; j++) { 121 auto cs = callSigns[j]; 122 LLVMValueRef func = llvmModule->GetFunction(j); 123 ASSERT(func != nullptr); 124 int delta = assembler->GetFpDeltaPrevFramSp(func, log); 125 ASSERT(delta >= 0 && (delta % sizeof(uintptr_t) == 0)); 126 uint32_t funcSize = 0; 127 if (j < funcCount - 1) { 128 funcSize = entrys[j + 1] - entrys[j]; 129 } else { 130 funcSize = codeBuff + assembler->GetSectionSize(ElfSecName::TEXT) - entrys[j]; 131 } 132 kungfu::CalleeRegAndOffsetVec info = assembler->GetCalleeReg2Offset(func, log); 133 stubInfo.AddEntry(cs->GetTargetKind(), false, false, cs->GetID(), entrys[j] - codeBuff, 134 AOTFileManager::STUB_FILE_INDEX, moduleIndex, delta, funcSize, info); 135 ASSERT(!cs->GetName().empty()); 136 addr2name[entrys[j]] = cs->GetName(); 137 } 138} 139 140void Module::CollectFuncEntryInfo(std::map<uintptr_t, std::string> &addr2name, AnFileInfo &aotInfo, uint32_t fileIndex, 141 uint32_t moduleIndex, const CompilerLog &log) 142{ 143#ifdef COMPILE_MAPLE 144 if (irModule_->GetModuleKind() != MODULE_LLVM) { 145 CollectFuncEntryInfoByLiteCG(addr2name, aotInfo, fileIndex, moduleIndex); 146 return; 147 } 148#endif 149 LLVMAssembler *assembler = static_cast<LLVMAssembler*>(assembler_); 150 auto engine = assembler->GetEngine(); 151 std::vector<std::tuple<uint64_t, size_t, int, bool>> funcInfo; // entry idx delta 152 std::vector<kungfu::CalleeRegAndOffsetVec> calleeSaveRegisters; // entry idx delta 153 // 1.Compile all functions and collect function infos 154 LLVMModule *llvmModule = static_cast<LLVMModule*>(irModule_); 155 llvmModule->IteratefuncIndexMap([&](size_t idx, LLVMValueRef func, bool isFastCall) { 156 uint64_t funcEntry = reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(engine, func)); 157 uint64_t length = 0; 158 std::string funcName(LLVMGetValueName2(func, reinterpret_cast<size_t *>(&length))); 159 ASSERT(length != 0); 160 addr2name[funcEntry] = funcName; 161 int delta = assembler->GetFpDeltaPrevFramSp(func, log); 162 ASSERT(delta >= 0 && (delta % sizeof(uintptr_t) == 0)); 163 funcInfo.emplace_back(std::tuple(funcEntry, idx, delta, isFastCall)); 164 kungfu::CalleeRegAndOffsetVec info = assembler->GetCalleeReg2Offset(func, log); 165 calleeSaveRegisters.emplace_back(info); 166 }); 167 // 2.After all functions compiled, the module sections would be fixed 168 uintptr_t textAddr = GetTextAddr(); 169 uint32_t textSize = GetTextSize(); 170 uintptr_t rodataAddrBeforeText = 0; 171 uint32_t rodataSizeBeforeText = 0; 172 uintptr_t rodataAddrAfterText = 0; 173 uint32_t rodataSizeAfterText = 0; 174 std::tie(rodataAddrBeforeText, rodataSizeBeforeText, rodataAddrAfterText, rodataSizeAfterText) = 175 GetMergedRODataAddrAndSize(textAddr); 176 aotInfo.AlignTextSec(AOTFileInfo::PAGE_ALIGN); 177 if (rodataSizeBeforeText != 0) { 178 aotInfo.UpdateCurTextSecOffset(rodataSizeBeforeText); 179 aotInfo.AlignTextSec(AOTFileInfo::TEXT_SEC_ALIGN); 180 } 181 182 const size_t funcCount = funcInfo.size(); 183 funcCount_ = funcCount; 184 startIndex_ = aotInfo.GetEntrySize(); 185 // 3.Add function entries based on the module sections 186 for (size_t i = 0; i < funcInfo.size(); i++) { 187 uint64_t funcEntry; 188 size_t idx; 189 int delta; 190 bool isFastCall; 191 uint32_t funcSize; 192 std::tie(funcEntry, idx, delta, isFastCall) = funcInfo[i]; 193 if (i < funcCount - 1) { 194 funcSize = std::get<0>(funcInfo[i + 1]) - funcEntry; 195 } else { 196 funcSize = textAddr + textSize - funcEntry; 197 } 198 auto found = addr2name[funcEntry].find(panda::ecmascript::JSPandaFile::ENTRY_FUNCTION_NAME); 199 bool isMainFunc = found != std::string::npos; 200 uint64_t offset = funcEntry - textAddr + aotInfo.GetCurTextSecOffset(); 201 aotInfo.AddEntry(CallSignature::TargetKind::JSFUNCTION, isMainFunc, isFastCall, idx, 202 offset, fileIndex, moduleIndex, delta, funcSize, calleeSaveRegisters[i]); 203 } 204 aotInfo.UpdateCurTextSecOffset(textSize); 205 if (rodataSizeAfterText != 0) { 206 aotInfo.AlignTextSec(AOTFileInfo::DATA_SEC_ALIGN); 207 aotInfo.UpdateCurTextSecOffset(rodataSizeAfterText); 208 } 209} 210 211#ifdef COMPILE_MAPLE 212void Module::CollectFuncEntryInfoByLiteCG(std::map<uintptr_t, std::string> &addr2name, AnFileInfo &aotInfo, 213 uint32_t fileIndex, uint32_t moduleIndex) 214{ 215 std::vector<std::tuple<uint64_t, size_t, int, bool>> funcInfo; // entry idx delta 216 std::vector<kungfu::CalleeRegAndOffsetVec> calleeSaveRegisters; // entry idx delta 217 // 1.Compile all functions and collect function infos 218 LMIRModule *lmirModule = static_cast<LMIRModule*>(irModule_); 219 LiteCGAssembler *assembler = static_cast<LiteCGAssembler*>(assembler_); 220 const auto &func2Addr = assembler->GetCodeInfo().GetFuncInfos(); 221 lmirModule->IteratefuncIndexMap([&](size_t idx, std::string funcName, bool isFastCall) { 222 auto itr = func2Addr.find(funcName); 223 if (itr == func2Addr.end()) { 224 LOG_COMPILER(FATAL) << "get function address from emitter failed"; 225 UNREACHABLE(); 226 } 227 uint64_t funcEntry = itr->second.addr; 228 addr2name[funcEntry] = funcName; 229 int delta = itr->second.fp2PrevFrameSpDelta; 230 ASSERT(delta >= 0 && (delta % sizeof(uintptr_t) == 0)); 231 funcInfo.emplace_back(std::tuple(funcEntry, idx, delta, isFastCall)); 232 kungfu::CalleeRegAndOffsetVec info = itr->second.calleeRegInfo; 233 calleeSaveRegisters.emplace_back(info); 234 }); 235 // 2.After all functions compiled, the module sections would be fixed 236 uint32_t textSize = GetTextSize(); 237 uint32_t rodataSizeBeforeText = 0; 238 uint32_t rodataSizeAfterText = 0; 239 240 aotInfo.AlignTextSec(AOTFileInfo::PAGE_ALIGN); 241 if (rodataSizeBeforeText != 0) { 242 aotInfo.UpdateCurTextSecOffset(rodataSizeBeforeText); 243 aotInfo.AlignTextSec(AOTFileInfo::TEXT_SEC_ALIGN); 244 } 245 246 const size_t funcCount = funcInfo.size(); 247 funcCount_ = funcCount; 248 startIndex_ = aotInfo.GetEntrySize(); 249 // 3.Add function entries based on the module sections 250 for (size_t i = 0; i < funcInfo.size(); i++) { 251 uint64_t funcEntry = 0; 252 size_t idx; 253 int delta; 254 bool isFastCall; 255 uint32_t funcSize; 256 std::tie(funcEntry, idx, delta, isFastCall) = funcInfo[i]; 257 if (i < funcCount - 1) { 258 funcSize = std::get<0>(funcInfo[i + 1]) - funcEntry; 259 } else { 260 funcSize = textSize - funcEntry; 261 } 262 auto found = addr2name[funcEntry].find(panda::ecmascript::JSPandaFile::ENTRY_FUNCTION_NAME); 263 bool isMainFunc = found != std::string::npos; 264 uint64_t offset = funcEntry; 265 aotInfo.AddEntry(CallSignature::TargetKind::JSFUNCTION, isMainFunc, isFastCall, idx, 266 offset, fileIndex, moduleIndex, delta, funcSize, calleeSaveRegisters[i]); 267 } 268 aotInfo.UpdateCurTextSecOffset(textSize); 269 if (rodataSizeAfterText != 0) { 270 aotInfo.AlignTextSec(AOTFileInfo::DATA_SEC_ALIGN); 271 aotInfo.UpdateCurTextSecOffset(rodataSizeAfterText); 272 } 273} 274#endif 275 276void Module::CollectModuleSectionDes(ModuleSectionDes &moduleDes) const 277{ 278 if (irModule_->GetModuleKind() != MODULE_LLVM) { 279 std::cout << "CollectModuleSectionDes is not supported for litecg currently" << std::endl; 280 return; 281 } 282 ASSERT(assembler_ != nullptr); 283 LLVMAssembler *assembler = static_cast<LLVMAssembler*>(assembler_); 284 assembler->IterateSecInfos([&](size_t i, std::pair<uint8_t *, size_t> secInfo) { 285 auto curSec = ElfSection(i); 286 ElfSecName sec = curSec.GetElfEnumValue(); 287 if (IsRelaSection(sec)) { 288 moduleDes.EraseSec(sec); 289 } else { // aot need relocated; stub don't need collect relocated section 290 moduleDes.SetSecAddrAndSize(sec, reinterpret_cast<uint64_t>(secInfo.first), secInfo.second); 291 moduleDes.SetStartIndex(startIndex_); 292 moduleDes.SetFuncCount(funcCount_); 293 } 294 }); 295 CollectStackMapDes(moduleDes); 296} 297 298void Module::CollectAnModuleSectionDes(ModuleSectionDes &moduleDes, uint64_t textOffset, 299 CGStackMapInfo &stackMapInfo) const 300{ 301 ASSERT(assembler_ != nullptr); 302 assembler_->IterateSecInfos([&](size_t i, std::pair<uint8_t *, size_t> secInfo) { 303 auto curSec = ElfSection(i); 304 ElfSecName sec = curSec.GetElfEnumValue(); 305 // aot need relocated; stub don't need collect relocated section 306 moduleDes.SetSecAddrAndSize(sec, reinterpret_cast<uint64_t>(secInfo.first), secInfo.second); 307 moduleDes.SetStartIndex(startIndex_); 308 moduleDes.SetFuncCount(funcCount_); 309 }); 310 CollectAnStackMapDes(moduleDes, textOffset, stackMapInfo); 311} 312 313uint32_t Module::GetSectionSize(ElfSecName sec) const 314{ 315 return assembler_->GetSectionSize(sec); 316} 317 318uintptr_t Module::GetSectionAddr(ElfSecName sec) const 319{ 320 return assembler_->GetSectionAddr(sec); 321} 322 323void Module::RunAssembler(const CompilerLog &log, bool fastCompileMode, bool isJit) 324{ 325 assembler_->Run(log, fastCompileMode, isJit); 326} 327 328void Module::DisassemblerFunc(std::map<uintptr_t, std::string> &addr2name, uint64_t textOffset, 329 const CompilerLog &log, const MethodLogList &logList, std::ostringstream &codeStream) 330{ 331 if (irModule_->GetModuleKind() != MODULE_LLVM) { 332 std::cout << "DisassemblerFunc is not supported for litecg currently" << std::endl; 333 return; 334 } 335 auto *assembler = static_cast<LLVMAssembler*>(assembler_); 336 assembler->Disassemble(addr2name, textOffset, log, logList, codeStream); 337} 338 339void Module::DestroyModule() 340{ 341 if (irModule_ != nullptr) { 342 delete irModule_; 343 irModule_ = nullptr; 344 } 345 if (assembler_ != nullptr) { 346 delete assembler_; 347 assembler_ = nullptr; 348 } 349} 350 351void StubFileGenerator::CollectAsmStubCodeInfo(std::map<uintptr_t, std::string> &addr2name, uint32_t bridgeModuleIdx) 352{ 353 uint32_t funSize = 0; 354 for (size_t i = 0; i < asmModule_.GetFunctionCount(); i++) { 355 auto cs = asmModule_.GetCSign(i); 356 auto entryOffset = asmModule_.GetFunction(cs->GetID()); 357 if (i < asmModule_.GetFunctionCount() - 1) { 358 auto nextcs = asmModule_.GetCSign(i + 1); 359 funSize = asmModule_.GetFunction(nextcs->GetID()) - entryOffset; 360 } else { 361 funSize = asmModule_.GetBufferSize() - entryOffset; 362 } 363 stubInfo_.AddEntry(cs->GetTargetKind(), false, false, cs->GetID(), entryOffset, 364 AOTFileManager::STUB_FILE_INDEX, bridgeModuleIdx, 0, funSize); 365 ASSERT(!cs->GetName().empty()); 366 addr2name[entryOffset] = cs->GetName(); 367 } 368} 369 370void StubFileGenerator::CollectCodeInfo() 371{ 372 std::map<uintptr_t, std::string> stubAddr2Name; 373 std::vector<std::vector<uintptr_t>> entryPoints(modulePackage_.size()); 374 375 if (!concurrentCompile_) { 376 for (size_t i = 0; i < modulePackage_.size(); ++i) { 377 entryPoints[i] = modulePackage_[i].GetFuncEntryPoints(); 378 } 379 } else if (!modulePackage_.empty()) { 380 // For first module, run it in current thread. 381 // For others, run them in child threads and wait for finish. 382 std::vector<std::thread> threads; 383 for (size_t i = 1; i < modulePackage_.size(); ++i) { 384 threads.emplace_back([&, i]() { 385 entryPoints[i] = modulePackage_[i].GetFuncEntryPoints(); 386 }); 387 } 388 entryPoints[0] = modulePackage_[0].GetFuncEntryPoints(); 389 for (auto& t : threads) { 390 if (t.joinable()) { 391 t.join(); 392 } 393 } 394 } 395 396 for (size_t i = 0; i < modulePackage_.size(); ++i) { 397 modulePackage_[i].CollectFuncEntryInfo(entryPoints[i], stubAddr2Name, stubInfo_, i, GetLog()); 398 ModuleSectionDes des; 399 modulePackage_[i].CollectModuleSectionDes(des); 400 stubInfo_.AddModuleDes(des); 401 } 402 std::map<uintptr_t, std::string> asmAddr2Name; 403 // idx for bridge module is the one after last module in modulePackage 404 CollectAsmStubCodeInfo(asmAddr2Name, modulePackage_.size()); 405 if (log_->OutputASM()) { 406 DisassembleAsmStubs(asmAddr2Name); 407 DisassembleEachFunc(stubAddr2Name); 408 } 409} 410 411void StubFileGenerator::DisassembleAsmStubs(std::map<uintptr_t, std::string> &addr2name) 412{ 413 std::string tri = cfg_.GetTripleStr(); 414 uint8_t *buf = reinterpret_cast<uint8_t*>(stubInfo_.GetAsmStubAddr()); 415 size_t size = stubInfo_.GetAsmStubSize(); 416 LLVMAssembler::Disassemble(&addr2name, tri, buf, size); 417} 418 419uint64_t AOTFileGenerator::RollbackTextSize(Module *module) 420{ 421 uint64_t textAddr = module->GetSectionAddr(ElfSecName::TEXT); 422 uint32_t textSize = module->GetSectionSize(ElfSecName::TEXT); 423 uint64_t rodataAddrBeforeText = 0; 424 uint32_t rodataSizeBeforeText = 0; 425 uint64_t rodataAddrAfterText = 0; 426 uint32_t rodataSizeAfterText = 0; 427 if (module->IsLLVM()) { 428 // In llvm the ro section is separated from the text section, but these all in text section in LiteCG. 429 std::tie(rodataAddrBeforeText, rodataSizeBeforeText, rodataAddrAfterText, rodataSizeAfterText) = 430 module->GetMergedRODataAddrAndSize(textAddr); 431 } 432 uint64_t textStart = 0; 433 if (rodataSizeAfterText == 0) { 434 textStart = aotInfo_.GetCurTextSecOffset() - textSize; 435 } else { 436 textStart = aotInfo_.GetCurTextSecOffset() - textSize - rodataSizeAfterText; 437 textStart = AlignDown(textStart, AOTFileInfo::DATA_SEC_ALIGN); 438 } 439 return textStart; 440} 441 442void AOTFileGenerator::CollectCodeInfo(Module *module, uint32_t moduleIdx) 443{ 444 std::map<uintptr_t, std::string> addr2name; 445 uint32_t lastEntryIdx = aotInfo_.GetEntrySize(); 446 pgo::ApEntityId abcId = INVALID_INDEX; 447 pgo::PGOProfilerManager::GetInstance()->GetPandaFileId(curCompileFileName_.c_str(), abcId); 448 module->CollectFuncEntryInfo(addr2name, aotInfo_, abcId, moduleIdx, GetLog()); 449 aotInfo_.MappingEntryFuncsToAbcFiles(curCompileFileName_, lastEntryIdx, aotInfo_.GetEntrySize()); 450 ModuleSectionDes des; 451 uint64_t textOffset = RollbackTextSize(module); 452 if (stackMapInfo_ == nullptr) { 453 LOG_ECMA(FATAL) << "stackMapInfo_ isn't be initialized"; 454 UNREACHABLE(); 455 } 456 module->CollectAnModuleSectionDes(des, textOffset, *stackMapInfo_); 457 458 aotInfo_.AddModuleDes(des); 459 if (module->IsLLVM() && log_->OutputASM()) { 460 module->DisassemblerFunc(addr2name, textOffset, *(log_), *(logList_), codeStream_); 461 } 462} 463 464Module* AOTFileGenerator::GetLatestModule() 465{ 466 return &modulePackage_.back(); 467} 468 469uint32_t AOTFileGenerator::GetModuleVecSize() const 470{ 471 return modulePackage_.size(); 472} 473 474Module* AOTFileGenerator::AddModule(const std::string &name, const std::string &triple, 475 [[maybe_unused]] LOptions option, bool logDebug, [[maybe_unused]] bool isJit) 476{ 477#ifdef COMPILE_MAPLE 478 if (useLiteCG_) { 479 LMIRModule *irModule = new LMIRModule(compilationEnv_->GetNativeAreaAllocator(), name, logDebug, triple, isJit); 480 LiteCGAssembler *ass = new LiteCGAssembler(*irModule, jitCodeSpace_, 481 compilationEnv_->GetJSOptions().GetCompilerCodegenOptions()); 482 modulePackage_.emplace_back(Module(irModule, ass)); 483 if (stackMapInfo_ == nullptr) { 484 stackMapInfo_ = new LiteCGStackMapInfo(); 485 } 486 return &modulePackage_.back(); 487 } 488#endif 489 LLVMModule *m = new LLVMModule(compilationEnv_->GetNativeAreaAllocator(), name, logDebug, triple); 490 LLVMAssembler *ass = new LLVMAssembler(m, jitCodeSpace_, option); 491 modulePackage_.emplace_back(Module(m, ass)); 492 if (stackMapInfo_ == nullptr) { 493 stackMapInfo_ = new LLVMStackMapInfo(); 494 } 495 return &modulePackage_.back(); 496} 497 498Module* StubFileGenerator::AddModule(NativeAreaAllocator *allocator, const std::string &name, const std::string &triple, 499 LOptions option, bool logDebug, StubFileKind kind) 500{ 501 LLVMModule* m = new LLVMModule(allocator, name, logDebug, triple); 502 switch (kind) { 503 case StubFileKind::BC: 504 m->SetUpForBytecodeHandlerStubs(); 505 break; 506 case StubFileKind::COM: 507 m->SetUpForCommonStubs(); 508 break; 509 case StubFileKind::BUILTIN: 510 m->SetUpForBuiltinsStubs(); 511 break; 512 case StubFileKind::BASELINE: 513 m->SetUpForBaselineStubs(); 514 break; 515 default: 516 LOG_ECMA(FATAL) << "unsupported stub file kind"; 517 UNREACHABLE(); 518 break; 519 } 520 LLVMAssembler* ass = new LLVMAssembler(m, jitCodeSpace_, option); 521 modulePackage_.emplace_back(Module(m, ass)); 522 return &modulePackage_.back(); 523} 524 525void StubFileGenerator::RunLLVMAssembler() 526{ 527 if (!concurrentCompile_) { 528 for (auto &m: modulePackage_) { 529 m.RunAssembler(*(this->log_), false); 530 } 531 } else if (!modulePackage_.empty()) { 532 // For first module, run it in current thread. 533 // For others, run them in child threads and wait for finish. 534 std::vector<std::thread> threads; 535 for (size_t i = 1; i < modulePackage_.size(); ++i) { 536 const CompilerLog &log = *(this->log_); 537 threads.emplace_back([&, i] { 538 modulePackage_[i].RunAssembler(log, false); 539 }); 540 } 541 modulePackage_[0].RunAssembler(*(this->log_), false); 542 for (auto& t : threads) { 543 if (t.joinable()) { 544 t.join(); 545 } 546 } 547 } 548} 549 550void StubFileGenerator::RunAsmAssembler() 551{ 552 NativeAreaAllocator allocator; 553 Chunk chunk(&allocator); 554 asmModule_.Run(&cfg_, &chunk); 555 556 auto buffer = asmModule_.GetBuffer(); 557 auto bufferSize = asmModule_.GetBufferSize(); 558 if (bufferSize == 0U) { 559 return; 560 } 561 stubInfo_.AddAsmStubELFInfo(asmModule_.GetCSigns(), asmModule_.GetStubsOffset()); 562 stubInfo_.FillAsmStubTempHolder(buffer, bufferSize); 563 stubInfo_.accumulateTotalSize(bufferSize); 564} 565 566void StubFileGenerator::SaveStubFile(const std::string &filename) 567{ 568 RunLLVMAssembler(); 569 RunAsmAssembler(); 570 CollectCodeInfo(); 571 stubInfo_.Save(filename, cfg_.GetTriple()); 572} 573 574void AOTFileGenerator::CompileLatestModuleThenDestroy(bool isJit) 575{ 576 Module *latestModule = GetLatestModule(); 577#ifdef COMPILE_MAPLE 578 static uint32_t lastModulePC = 0; 579 if (useLiteCG_ && compilationEnv_->IsJitCompiler()) { 580 lastModulePC = 0; 581 } 582 if (latestModule->GetModule()->GetModuleKind() != MODULE_LLVM) { 583 LMIRModule *lmirModule = static_cast<LMIRModule*>(latestModule->GetModule()); 584 lastModulePC = AlignUp(lastModulePC, AOTFileInfo::PAGE_ALIGN); 585 lmirModule->GetModule()->SetLastModulePC(lastModulePC); 586 // pass triple to litecg 587 lmirModule->GetModule()->SetIsAArch64(isAArch64()); 588 } 589#endif 590 ASSERT(GetModuleVecSize() > 0); 591 uint32_t latestModuleIdx = GetModuleVecSize() - 1; 592 { 593 TimeScope timescope("LLVMIROpt", const_cast<CompilerLog *>(log_)); 594 bool fastCompileMode = compilationEnv_->GetJSOptions().GetFastAOTCompileMode(); 595 latestModule->RunAssembler(*(log_), fastCompileMode, isJit); 596 } 597 { 598 TimeScope timescope("LLVMCodeGen", const_cast<CompilerLog *>(log_)); 599 CollectCodeInfo(latestModule, latestModuleIdx); 600 } 601 // message has been put into aotInfo, so latestModule could be destroyed 602#ifdef COMPILE_MAPLE 603 if (latestModule->GetModule()->GetModuleKind() != MODULE_LLVM) { 604 LMIRModule *lmirModule = static_cast<LMIRModule*>(latestModule->GetModule()); 605 lastModulePC = lmirModule->GetModule()->GetCurModulePC(); 606 } 607#endif 608 latestModule->DestroyModule(); 609} 610 611void AOTFileGenerator::DestroyCollectedStackMapInfo() 612{ 613 if (stackMapInfo_ != nullptr) { 614 delete stackMapInfo_; 615 stackMapInfo_ = nullptr; 616 } 617} 618 619void AOTFileGenerator::GenerateMergedStackmapSection() 620{ 621 ArkStackMapBuilder builder; 622 std::shared_ptr<uint8_t> ptr = nullptr; 623 uint32_t size = 0; 624 if (stackMapInfo_ == nullptr) { 625 LOG_ECMA(FATAL) << "stackMapInfo_ isn't be initialized"; 626 UNREACHABLE(); 627 } 628 std::tie(ptr, size) = builder.GenerateArkStackMap(*stackMapInfo_, cfg_.GetTriple()); 629 aotInfo_.UpdateStackMap(ptr, size, 0); 630 DestroyCollectedStackMapInfo(); 631} 632 633bool AOTFileGenerator::CreateDirIfNotExist(const std::string &filename) 634{ 635 std::string realPath; 636 if (!panda::ecmascript::RealPath(filename, realPath, false)) { 637 return false; 638 } 639 auto index = realPath.find_last_of('/'); 640 if (index == std::string::npos) { 641 return true; 642 } 643 std::string path = realPath.substr(0, index); 644 if (!panda::ecmascript::ForceCreateDirectory(path)) { 645 LOG_COMPILER(ERROR) << "Fail to make dir: " << path; 646 return false; 647 } 648 return panda::ecmascript::SetDirModeAsDefault(path); 649} 650 651bool AOTFileGenerator::SaveAOTFile(const std::string &filename, const std::string &appSignature) 652{ 653 if (aotInfo_.GetTotalCodeSize() == 0) { 654 LOG_COMPILER(WARN) << "error: code size of generated an file is empty!"; 655 return false; 656 } 657 if (!CreateDirIfNotExist(filename)) { 658 LOG_COMPILER(ERROR) << "Fail to access dir: " << filename; 659 return false; 660 } 661 PrintMergedCodeComment(); 662 GenerateMergedStackmapSection(); 663 aotInfo_.GenerateMethodToEntryIndexMap(); 664 if (!aotInfo_.Save(filename, cfg_.GetTriple())) { 665 LOG_COMPILER(ERROR) << "Fail to save an file: " << filename; 666 return false; 667 } 668 if (!panda::ecmascript::SetFileModeAsDefault(filename)) { 669 LOG_COMPILER(ERROR) << "Fail to set an file mode:" << filename; 670 return false; 671 } 672 SetSecurityLabel(filename); 673 panda::ecmascript::CodeSignatureForAOTFile(filename, appSignature); 674 return true; 675} 676 677void AOTFileGenerator::SaveEmptyAOTFile(const std::string& filename, const std::string& appSignature, bool isAnFile) 678{ 679 if (!CreateDirIfNotExist(filename)) { 680 LOG_COMPILER(ERROR) << "Fail to access dir: " << filename; 681 return; 682 } 683 std::string realPath; 684 if (!RealPath(filename, realPath, false)) { 685 LOG_COMPILER(ERROR) << "Fail to get realPath: " << filename; 686 return; 687 } 688 if (FileExist(realPath.c_str())) { 689 LOG_COMPILER(ERROR) << "AOT file: " << realPath << " exist, skip create empty file"; 690 return; 691 } 692 const char* rawPath = realPath.c_str(); 693 std::ofstream file(rawPath, std::ofstream::binary); 694 file.close(); 695 if (!panda::ecmascript::SetFileModeAsDefault(filename)) { 696 LOG_COMPILER(ERROR) << "Fail to set file mode: " << filename; 697 } 698 if (isAnFile) { 699 panda::ecmascript::CodeSignatureForAOTFile(filename, appSignature); 700 } 701 LOG_COMPILER(ERROR) << "create empty AOT file: " << realPath << " due to illegal AP file"; 702} 703 704bool AOTFileGenerator::GetMemoryCodeInfos(MachineCodeDesc &machineCodeDesc) 705{ 706 if (aotInfo_.GetTotalCodeSize() == 0) { 707 LOG_COMPILER(WARN) << "error: code size of generated an file is empty!"; 708 return false; 709 } 710 711 if (log_->OutputASM()) { 712 PrintMergedCodeComment(); 713 } 714 GenerateMergedStackmapSection(); 715 716 // get func entry Map 717 aotInfo_.GenerateMethodToEntryIndexMap(); 718 719 uint64_t funcEntryAddr = reinterpret_cast<uint64_t>(aotInfo_.GetStubs().data()); 720 ASSERT(aotInfo_.GetStubs().size() <= 2); // jsfunc + __llvm_deoptimize, 2 : size 721 uint32_t funcEntrySize = sizeof(AOTFileInfo::FuncEntryDes) * aotInfo_.GetStubs().size(); 722 723 ASSERT(aotInfo_.GetModuleSectionDes().size() == 1); 724 auto &moduleSectionDes = aotInfo_.GetModuleSectionDes()[0]; 725 // get code data 726 uint64_t textAddr = moduleSectionDes.GetSecAddr(ElfSecName::TEXT); 727 size_t textSize = moduleSectionDes.GetSecSize(ElfSecName::TEXT); 728 729 uint64_t rodataAddrBeforeText = 0; 730 uint32_t rodataSizeBeforeText = 0; 731 uint64_t rodataAddrAfterText = 0; 732 uint32_t rodataSizeAfterText = 0; 733 std::tie(rodataAddrBeforeText, rodataSizeBeforeText, rodataAddrAfterText, rodataSizeAfterText) = 734 moduleSectionDes.GetMergedRODataAddrAndSize(textAddr); 735 736 machineCodeDesc.rodataAddrBeforeText = rodataAddrBeforeText; 737 machineCodeDesc.rodataSizeBeforeText = rodataSizeBeforeText; 738 machineCodeDesc.rodataAddrAfterText = rodataAddrAfterText; 739 machineCodeDesc.rodataSizeAfterText = rodataSizeAfterText; 740 741#ifdef JIT_ENABLE_CODE_SIGN 742 machineCodeDesc.codeSigner = 0; 743 JitSignCode *singleton = JitSignCode::GetInstance(); 744 if (singleton->GetCodeSigner() != 0) { 745 LOG_JIT(DEBUG) << "In GetMemoryCodeInfos, signer = " << singleton->GetCodeSigner(); 746 LOG_JIT(DEBUG) << " signTableSize = " << singleton->signTableSize_; 747 machineCodeDesc.codeSigner = reinterpret_cast<uintptr_t>(singleton->GetCodeSigner()); 748 } 749#endif 750 751 uint64_t stackMapPtr = reinterpret_cast<uint64_t>(moduleSectionDes.GetArkStackMapSharePtr().get()); 752 size_t stackMapSize = moduleSectionDes.GetArkStackMapSize(); 753 754 machineCodeDesc.codeAddr = textAddr; 755 machineCodeDesc.codeSize = textSize; 756 machineCodeDesc.funcEntryDesAddr = funcEntryAddr; 757 machineCodeDesc.funcEntryDesSize = funcEntrySize; 758 machineCodeDesc.stackMapOrOffsetTableAddr = stackMapPtr; 759 machineCodeDesc.stackMapOrOffsetTableSize = stackMapSize; 760 machineCodeDesc.codeType = MachineCodeType::FAST_JIT_CODE; 761 762 if (Jit::GetInstance()->IsEnableJitFort() && Jit::GetInstance()->IsEnableAsyncCopyToFort() && 763 JitCompiler::AllocFromFortAndCopy(*compilationEnv_, machineCodeDesc) == false) { 764 return false; 765 } 766 return true; 767} 768 769void AOTFileGenerator::JitCreateLitecgModule() 770{ 771#ifdef COMPILE_MAPLE 772 Module *latestModule = GetLatestModule(); 773 if (latestModule->GetModule()->GetModuleKind() != MODULE_LLVM) { 774 LMIRModule *lmirModule = static_cast<LMIRModule*>(latestModule->GetModule()); 775 lmirModule->JitCreateLitecgModule(); 776 } 777#endif 778} 779 780bool AOTFileGenerator::isAArch64() const 781{ 782 return cfg_.IsAArch64(); 783} 784 785bool AOTFileGenerator::SaveSnapshotFile() 786{ 787 TimeScope timescope("LLVMCodeGenPass-AI", const_cast<CompilerLog *>(log_)); 788 Snapshot snapshot(compilationEnv_->GetEcmaVM()); 789 const CString snapshotPath(compilationEnv_->GetJSOptions().GetAOTOutputFile().c_str()); 790 const auto &methodToEntryIndexMap = aotInfo_.GetMethodToEntryIndexMap(); 791 PGOTypeManager *ptManager = compilationEnv_->GetPTManager(); 792 ptManager->GetAOTSnapshot().ResolveSnapshotData(methodToEntryIndexMap); 793 794 CString aiPath = snapshotPath + AOTFileManager::FILE_EXTENSION_AI; 795 if (!CreateDirIfNotExist(aiPath.c_str())) { 796 LOG_COMPILER(ERROR) << "Fail to access dir: " << aiPath; 797 return false; 798 } 799 snapshot.Serialize(aiPath); 800 if (!panda::ecmascript::SetFileModeAsDefault(aiPath.c_str())) { 801 LOG_COMPILER(ERROR) << "Fail to set ai file mode:" << aiPath; 802 return false; 803 } 804 SetSecurityLabel(aiPath.c_str()); 805 return true; 806} 807} // namespace panda::ecmascript::kungfu 808