• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_LLVM_CODEGEN_H
17 #define ECMASCRIPT_COMPILER_LLVM_CODEGEN_H
18 
19 #include <iostream>
20 #include <list>
21 #include <map>
22 #include <vector>
23 
24 #include "ecmascript/compiler/binary_section.h"
25 #include "ecmascript/compiler/code_generator.h"
26 #include "ecmascript/compiler/compiler_log.h"
27 #include "ecmascript/compiler/llvm_ir_builder.h"
28 #include "ecmascript/ecma_macros.h"
29 #include "ecmascript/js_thread.h"
30 
31 #if defined(__clang__)
32 #pragma clang diagnostic push
33 #pragma clang diagnostic ignored "-Wshadow"
34 #pragma clang diagnostic ignored "-Wunused-parameter"
35 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
36 #elif defined(__GNUC__)
37 #pragma GCC diagnostic push
38 #pragma GCC diagnostic ignored "-Wshadow"
39 #pragma GCC diagnostic ignored "-Wunused-parameter"
40 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
41 #endif
42 
43 #include "ecmascript/mem/machine_code.h"
44 #include "ecmascript/mem/region.h"
45 #include "llvm-c/Analysis.h"
46 #include "llvm-c/Core.h"
47 #include "llvm-c/ExecutionEngine.h"
48 #include "llvm-c/Target.h"
49 #include "llvm-c/Transforms/PassManagerBuilder.h"
50 #include "llvm-c/Transforms/Scalar.h"
51 #include "llvm-c/Types.h"
52 #include "llvm/ExecutionEngine/Interpreter.h"
53 #include "llvm/IR/Instructions.h"
54 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
55 #include "llvm/ExecutionEngine/MCJIT.h"
56 #include "llvm/Support/Host.h"
57 
58 #if defined(__clang__)
59 #pragma clang diagnostic pop
60 #elif defined(__GNUC__)
61 #pragma GCC diagnostic pop
62 #endif
63 
64 namespace panda::ecmascript::kungfu {
65 struct CodeInfo {
66     using sectionInfo = std::pair<uint8_t *, size_t>;
CodeInfoCodeInfo67     CodeInfo()
68     {
69         ASSERT(REQUIRED_SECS_LIMIT == AlignUp(REQUIRED_SECS_LIMIT, PageSize()));
70 #ifdef PANDA_TARGET_MACOS
71         reqSecs_ = static_cast<uint8_t *>(PageMap(REQUIRED_SECS_LIMIT, PAGE_PROT_READWRITE).GetMem());
72 #else
73         reqSecs_ = static_cast<uint8_t *>(PageMap(REQUIRED_SECS_LIMIT, PAGE_PROT_EXEC_READWRITE).GetMem());
74 #endif
75         if (reqSecs_ == reinterpret_cast<uint8_t *>(-1)) {
76             reqSecs_ = nullptr;
77         }
78         ASSERT(UNREQUIRED_SECS_LIMIT == AlignUp(UNREQUIRED_SECS_LIMIT, PageSize()));
79 #ifdef PANDA_TARGET_MACOS
80         unreqSecs_ = static_cast<uint8_t *>(PageMap(UNREQUIRED_SECS_LIMIT, PAGE_PROT_READWRITE).GetMem());
81 #else
82         unreqSecs_ = static_cast<uint8_t *>(PageMap(UNREQUIRED_SECS_LIMIT, PAGE_PROT_EXEC_READWRITE).GetMem());
83 #endif
84         if (unreqSecs_ == reinterpret_cast<uint8_t *>(-1)) {
85             unreqSecs_ = nullptr;
86         }
87         secInfos_.fill(std::make_pair(nullptr, 0));
88     }
~CodeInfoCodeInfo89     ~CodeInfo()
90     {
91         Reset();
92         if (reqSecs_ != nullptr) {
93             PageUnmap(MemMap(reqSecs_, REQUIRED_SECS_LIMIT));
94         }
95         reqSecs_ = nullptr;
96         if (unreqSecs_ != nullptr) {
97             PageUnmap(MemMap(unreqSecs_, UNREQUIRED_SECS_LIMIT));
98         }
99         unreqSecs_ = nullptr;
100     }
101 
102     uint8_t *AllocaInReqSecBuffer(uintptr_t size, bool alignFlag = true)
103     {
104         return Alloca(size, reqSecs_, reqBufPos_, alignFlag);
105     }
106 
AllocaInNotReqSecBufferCodeInfo107     uint8_t *AllocaInNotReqSecBuffer(uintptr_t size)
108     {
109         return Alloca(size, unreqSecs_, unreqBufPos_);
110     }
111 
AllocaCodeSectionCodeInfo112     uint8_t *AllocaCodeSection(uintptr_t size, const char *sectionName)
113     {
114         // if have got section, don't use align.
115         uint8_t *addr = AllocaInReqSecBuffer(size, false);
116         auto curSec = ElfSection(sectionName);
117         codeInfo_.push_back({addr, size});
118         if (curSec.isValidAOTSec()) {
119             secInfos_[curSec.GetIntIndex()] = std::make_pair(addr, size);
120         }
121         return addr;
122     }
123 
AllocaDataSectionCodeInfo124     uint8_t *AllocaDataSection(uintptr_t size, const char *sectionName)
125     {
126         uint8_t *addr = nullptr;
127         auto curSec = ElfSection(sectionName);
128         // rodata section needs 16 bytes alignment
129         if (curSec.InRodataSection()) {
130             size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_REGION));
131         }
132         addr = curSec.isSequentialAOTSec() ? AllocaInReqSecBuffer(size) : AllocaInNotReqSecBuffer(size);
133         if (curSec.isValidAOTSec()) {
134             secInfos_[curSec.GetIntIndex()] = std::make_pair(addr, size);
135         }
136         return addr;
137     }
138 
ResetCodeInfo139     void Reset()
140     {
141         codeInfo_.clear();
142         reqBufPos_ = 0;
143         unreqBufPos_ = 0;
144     }
145 
GetSectionAddrCodeInfo146     uint8_t *GetSectionAddr(ElfSecName sec) const
147     {
148         auto curSection = ElfSection(sec);
149         auto idx = curSection.GetIntIndex();
150         return const_cast<uint8_t *>(secInfos_[idx].first);
151     }
152 
GetSectionSizeCodeInfo153     size_t GetSectionSize(ElfSecName sec) const
154     {
155         auto curSection = ElfSection(sec);
156         auto idx = curSection.GetIntIndex();
157         return secInfos_[idx].second;
158     }
159 
GetCodeInfoCodeInfo160     std::vector<std::pair<uint8_t *, uintptr_t>> GetCodeInfo() const
161     {
162         return codeInfo_;
163     }
164 
165     template <class Callback>
IterateSecInfosCodeInfo166     void IterateSecInfos(const Callback &cb) const
167     {
168         for (size_t i = 0; i < secInfos_.size(); i++) {
169             if (secInfos_[i].second == 0) {
170                 continue;
171             }
172             cb(i, secInfos_[i]);
173         }
174     }
175 
176 private:
177     static constexpr size_t REQUIRED_SECS_LIMIT = (1 << 29);  // 512M
178     static constexpr size_t UNREQUIRED_SECS_LIMIT = (1 << 28);  // 256M
179     // start point of the buffer reserved for sections required in executing phase
180     uint8_t *reqSecs_ {nullptr};
181     size_t reqBufPos_ {0};
182     // start point of the buffer reserved for sections not required in executing phase
183     uint8_t *unreqSecs_ {nullptr};
184     size_t unreqBufPos_ {0};
185     std::array<sectionInfo, static_cast<int>(ElfSecName::SIZE)> secInfos_;
186     std::vector<std::pair<uint8_t *, uintptr_t>> codeInfo_ {}; // info for disasssembler, planed to be deprecated
187 
188     uint8_t *Alloca(uintptr_t size, uint8_t *bufBegin, size_t &curPos, bool alignFlag = true)
189     {
190         // align up for rodata section
191         if (alignFlag) {
192             size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_REGION));
193         }
194         uint8_t *addr = nullptr;
195         size_t limit = (bufBegin == reqSecs_) ? REQUIRED_SECS_LIMIT : UNREQUIRED_SECS_LIMIT;
196         if (curPos + size > limit) {
197             LOG_COMPILER(ERROR) << std::hex << "Alloca Section failed. Current curPos:" << curPos
198                       << " plus size:" << size << "exceed limit:" << limit;
199             return nullptr;
200         }
201         addr = bufBegin + curPos;
202         curPos += size;
203         return addr;
204     }
205 };
206 
207 struct LOptions {
208     uint32_t optLevel : 2; // 2 bits for optimized level 0-4
209     uint32_t genFp : 1; // 1 bit for whether to generated frame pointer or not
210     uint32_t relocMode : 3; // 3 bits for relocation mode
211     // 3: default optLevel, 1: generating fp, 2: PIC mode
LOptionsLOptions212     LOptions() : optLevel(3), genFp(1), relocMode(2) {};
LOptionsLOptions213     LOptions(size_t level, bool genFp, size_t relocMode) : optLevel(level), genFp(genFp), relocMode(relocMode) {};
214 };
215 
216 class LLVMAssembler {
217 public:
218     explicit LLVMAssembler(LLVMModuleRef module, LOptions option = LOptions());
219     virtual ~LLVMAssembler();
220     void Run(const CompilerLog &log);
GetEngine()221     const LLVMExecutionEngineRef &GetEngine()
222     {
223         return engine_;
224     }
225     void Disassemble(const std::map<uintptr_t, std::string> &addr2name,
226                      const CompilerLog &log, const MethodLogList &logList) const;
227     static void Disassemble(uint8_t *buf, size_t size);
228     static int GetFpDeltaPrevFramSp(LLVMValueRef fn, const CompilerLog &log);
229     static kungfu::CalleeRegAndOffsetVec GetCalleeReg2Offset(LLVMValueRef fn, const CompilerLog &log);
230 
GetSectionAddr(ElfSecName sec)231     uintptr_t GetSectionAddr(ElfSecName sec) const
232     {
233         return reinterpret_cast<uintptr_t>(codeInfo_.GetSectionAddr(sec));
234     }
235 
GetSectionSize(ElfSecName sec)236     uint32_t GetSectionSize(ElfSecName sec) const
237     {
238         return static_cast<uint32_t>(codeInfo_.GetSectionSize(sec));
239     }
240 
GetFuncPtrFromCompiledModule(LLVMValueRef function)241     void *GetFuncPtrFromCompiledModule(LLVMValueRef function)
242     {
243         return LLVMGetPointerToGlobal(engine_, function);
244     }
245 
246     template <class Callback>
IterateSecInfos(const Callback & cb)247     void IterateSecInfos(const Callback &cb) const
248     {
249         codeInfo_.IterateSecInfos(cb);
250     }
251 
252 private:
253     void UseRoundTripSectionMemoryManager();
254     bool BuildMCJITEngine();
255     void BuildAndRunPasses();
256     void Initialize(LOptions option);
257     static void PrintInstAndStep(unsigned &pc, uint8_t **byteSp, uintptr_t &numBytes, size_t instSize, char *outString,
258         bool logFlag = true);
259 
260     LLVMMCJITCompilerOptions options_ {};
261     LLVMModuleRef module_;
262     LLVMExecutionEngineRef engine_ {nullptr};
263     char *error_ {nullptr};
264     struct CodeInfo codeInfo_ {};
265 };
266 
267 class LLVMIRGeneratorImpl : public CodeGeneratorImpl {
268 public:
LLVMIRGeneratorImpl(LLVMModule * module,bool enableLog)269     explicit LLVMIRGeneratorImpl(LLVMModule *module, bool enableLog)
270         : module_(module), enableLog_(enableLog) {}
271     ~LLVMIRGeneratorImpl() = default;
272     void GenerateCodeForStub(Circuit *circuit, const ControlFlowGraph &graph, size_t index,
273                              const CompilationConfig *cfg) override;
274     void GenerateCode(Circuit *circuit, const ControlFlowGraph &graph, const CompilationConfig *cfg,
275         const MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile) override;
276 
IsLogEnabled()277     bool IsLogEnabled() const
278     {
279         return enableLog_;
280     }
281 
282 private:
283     LLVMModule *module_;
284     bool enableLog_ {false};
285 };
286 }  // namespace panda::ecmascript::kungfu
287 #endif  // ECMASCRIPT_COMPILER_LLVM_CODEGEN_H
288