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#ifndef ECMASCRIPT_COMPILER_FILE_GENERATORS_H
17#define ECMASCRIPT_COMPILER_FILE_GENERATORS_H
18
19#include "ecmascript/base/number_helper.h"
20#include "ecmascript/common.h"
21#include "ecmascript/compiler/aot_file/aot_file_manager.h"
22#include "ecmascript/compiler/assembler_module.h"
23#include "ecmascript/compiler/codegen/llvm/llvm_codegen.h"
24#include "ecmascript/compiler/codegen/llvm/llvm_ir_builder.h"
25#include "ecmascript/compiler/compiler_log.h"
26#include "ecmascript/compiler/ir_module.h"
27#include "ecmascript/compiler/jit_compilation_env.h"
28#include "ecmascript/stackmap/cg_stackmap.h"
29#include "ecmascript/mem/machine_code.h"
30
31namespace panda::ecmascript::kungfu {
32class Module {
33public:
34    Module() = default;
35    Module(IRModule *module, Assembler *assembler)
36        : irModule_(module), assembler_(assembler)
37    {
38    }
39
40    std::vector<uintptr_t> GetFuncEntryPoints();
41
42    void CollectFuncEntryInfo(const std::vector<uintptr_t>& entrys, std::map<uintptr_t, std::string> &addr2name,
43                              StubFileInfo &stubInfo, uint32_t moduleIndex, const CompilerLog &log);
44
45    void CollectFuncEntryInfo(std::map<uintptr_t, std::string> &addr2name, AnFileInfo &aotInfo, uint32_t fileIndex,
46                              uint32_t moduleIndex, const CompilerLog &log);
47
48#ifdef COMPILE_MAPLE
49    void CollectFuncEntryInfoByLiteCG(std::map<uintptr_t, std::string> &addr2name, AnFileInfo &aotInfo,
50                                      uint32_t fileIndex, uint32_t moduleIndex);
51#endif
52
53    bool IsRelaSection(ElfSecName sec) const
54    {
55        return sec == ElfSecName::RELATEXT;
56    }
57
58    void CollectModuleSectionDes(ModuleSectionDes &moduleDes) const;
59
60    void CollectAnModuleSectionDes(ModuleSectionDes &moduleDes, uint64_t textOffset,
61                                   CGStackMapInfo &stackMapInfo) const;
62
63    void CollectStackMapDes(ModuleSectionDes &moduleDes) const;
64
65    void CollectAnStackMapDes(ModuleSectionDes& des, uint64_t textOffset,
66                              CGStackMapInfo &stackMapInfo) const;
67
68    uint32_t GetSectionSize(ElfSecName sec) const;
69
70    uintptr_t GetSectionAddr(ElfSecName sec) const;
71
72    std::tuple<uint64_t, uint32_t, uint64_t, uint32_t> GetMergedRODataAddrAndSize(uint64_t textAddr) const
73    {
74        uint64_t addrBeforeText = base::MAX_UINT64_VALUE;
75        uint32_t sizeBeforeText = 0;
76        uint64_t addrAfterText = base::MAX_UINT64_VALUE;
77        uint32_t sizeAfterText = 0;
78        for (uint8_t i = static_cast<uint8_t>(ElfSecName::RODATA); i <= static_cast<uint8_t>(ElfSecName::RODATA_CST32);
79             i++) {
80            UpdateRODataInfo(textAddr, addrBeforeText, sizeBeforeText, addrAfterText, sizeAfterText,
81                static_cast<ElfSecName>(i));
82        }
83        return std::make_tuple(addrBeforeText, sizeBeforeText, addrAfterText, sizeAfterText);
84    }
85
86    void RunAssembler(const CompilerLog &log, bool fastCompileMode, bool isJit = false);
87
88    void DisassemblerFunc(std::map<uintptr_t, std::string> &addr2name, uint64_t textOffset, const CompilerLog &log,
89                          const MethodLogList &logList, std::ostringstream &codeStream);
90
91    void DestroyModule();
92
93    IRModule* GetModule() const
94    {
95        return irModule_;
96    }
97
98    bool IsLLVM() const
99    {
100        return irModule_->GetModuleKind() == MODULE_LLVM;
101    }
102
103private:
104    uintptr_t GetTextAddr() const
105    {
106        return assembler_->GetSectionAddr(ElfSecName::TEXT);
107    }
108
109    uint32_t GetTextSize() const
110    {
111        return assembler_->GetSectionSize(ElfSecName::TEXT);
112    }
113
114    void UpdateRODataInfo(uint64_t textAddr, uint64_t &addrBeforeText, uint32_t &sizeBeforeText,
115                          uint64_t &addrAfterText, uint32_t &sizeAfterText, ElfSecName sec) const
116    {
117        uint64_t curSectionAddr = GetSectionAddr(sec);
118        if (curSectionAddr == 0) {
119            ASSERT(GetSectionSize(sec) == 0);
120            return;
121        }
122        ASSERT(curSectionAddr != textAddr);
123        if (curSectionAddr < textAddr) {
124            addrBeforeText = (curSectionAddr < addrBeforeText) ? curSectionAddr : addrBeforeText;
125            sizeBeforeText += GetSectionSize(sec);
126        } else {
127            addrAfterText = (curSectionAddr < addrAfterText) ? curSectionAddr : addrAfterText;
128            sizeAfterText += GetSectionSize(sec);
129        }
130    }
131
132    IRModule *irModule_ {nullptr};
133    Assembler *assembler_ {nullptr};
134    // record current module first function index in StubFileInfo/AnFileInfo
135    uint32_t startIndex_ {static_cast<uint32_t>(-1)};
136    uint32_t funcCount_ {0};
137};
138
139class FileGenerator {
140public:
141    FileGenerator(const CompilerLog *log, const MethodLogList *logList) : log_(log), logList_(logList) {};
142    virtual ~FileGenerator()
143    {
144        codeStream_.clear();
145        codeStream_.str("");
146    }
147
148    const CompilerLog GetLog() const
149    {
150        return *log_;
151    }
152
153    void PrintMergedCodeComment()
154    {
155        LOG_COMPILER(INFO) << "\n" << codeStream_.str();
156    }
157
158protected:
159    std::vector<Module> modulePackage_ {};
160    const CompilerLog *log_ {nullptr};
161    const MethodLogList *logList_ {nullptr};
162    std::ostringstream codeStream_;
163
164    virtual void RunLLVMAssembler()
165    {
166        for (auto m : modulePackage_) {
167            m.RunAssembler(*(log_), false);
168        }
169    }
170
171    void DestroyModule()
172    {
173        for (auto m : modulePackage_) {
174            m.DestroyModule();
175        }
176    }
177
178    void CollectStackMapDes(ModuleSectionDes& des);
179};
180
181class AOTFileGenerator : public FileGenerator {
182public:
183    AOTFileGenerator(const CompilerLog *log, const MethodLogList *logList, CompilationEnv *env,
184                     const std::string &triple, bool useLiteCG = false)
185        : FileGenerator(log, logList), compilationEnv_(env), cfg_(triple), useLiteCG_(useLiteCG) {}
186
187    ~AOTFileGenerator() override = default;
188
189    Module* GetLatestModule();
190
191    uint32_t GetModuleVecSize() const;
192
193    Module* AddModule(const std::string &name, const std::string &triple, LOptions option, bool logDebug,
194        bool isJit = false);
195
196    void CompileLatestModuleThenDestroy(bool isJit = false);
197
198    void DestroyCollectedStackMapInfo();
199
200    void GenerateMergedStackmapSection();
201
202    static bool CreateDirIfNotExist(const std::string& filename);
203
204    bool SetFileModeAsDefault(const std::string &filename);
205
206    // save function for aot files containing normal func translated from JS/TS
207    bool SaveAOTFile(const std::string &filename, const std::string &appSignature);
208
209    static void SaveEmptyAOTFile(const std::string& filename, const std::string& appSignature, bool isAnFile);
210
211    bool SaveSnapshotFile();
212
213    void SetCurrentCompileFileName(CString fileName)
214    {
215        curCompileFileName_ = fileName.c_str();
216    }
217
218    bool GetMemoryCodeInfos(MachineCodeDesc &machineCodeDesc);
219    void JitCreateLitecgModule();
220    bool isAArch64() const;
221private:
222    // collect aot component info
223    void CollectCodeInfo(Module *module, uint32_t moduleIdx);
224
225    uint64_t RollbackTextSize(Module *module);
226
227    AnFileInfo aotInfo_;
228    CGStackMapInfo *stackMapInfo_ = nullptr;
229    CompilationEnv *compilationEnv_ {nullptr};
230    CompilationConfig cfg_;
231    std::string curCompileFileName_;
232    // MethodID->EntryIndex
233    std::map<uint32_t, uint32_t> methodToEntryIndexMap_ {};
234    const bool useLiteCG_;
235    CodeInfo::CodeSpaceOnDemand jitCodeSpace_ {};
236};
237
238enum class StubFileKind {
239    BC,
240    COM,
241    BUILTIN,
242    BASELINE
243};
244
245class StubFileGenerator : public FileGenerator {
246public:
247    StubFileGenerator(const CompilerLog* log, const MethodLogList* logList, const std::string& triple,
248                      bool concurrentCompile)
249        : FileGenerator(log, logList),
250          cfg_(triple),
251          concurrentCompile_(concurrentCompile)
252    {
253    }
254    ~StubFileGenerator() override = default;
255
256    Module* AddModule(NativeAreaAllocator *allocator, const std::string &name, const std::string &triple,
257                      LOptions option, bool logDebug, StubFileKind k);
258
259    void DisassembleEachFunc(std::map<uintptr_t, std::string> &addr2name)
260    {
261        for (auto m : modulePackage_) {
262            m.DisassemblerFunc(addr2name, 0, *(log_), *(logList_), codeStream_);
263        }
264        PrintMergedCodeComment();
265    }
266
267    void DisassembleAsmStubs(std::map<uintptr_t, std::string> &addr2name);
268    // save function funcs for aot files containing stubs
269    void SaveStubFile(const std::string &filename);
270protected:
271    void RunLLVMAssembler() override;
272private:
273    void RunAsmAssembler();
274    void CollectAsmStubCodeInfo(std::map<uintptr_t, std::string> &addr2name, uint32_t bridgeModuleIdx);
275    void CollectCodeInfo();
276
277    StubFileInfo stubInfo_;
278    AssemblerModule asmModule_;
279    CompilationConfig cfg_;
280    CodeInfo::CodeSpaceOnDemand jitCodeSpace_ {};
281    bool concurrentCompile_ {false};
282};
283}  // namespace panda::ecmascript::kungfu
284#endif // ECMASCRIPT_COMPILER_FILE_GENERATORS_H
285