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