• 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 "ecmascript/compiler/binary_section.h"
20 #include "ecmascript/compiler/code_generator.h"
21 
22 #if defined(__clang__)
23 #pragma clang diagnostic push
24 #pragma clang diagnostic ignored "-Wshadow"
25 #pragma clang diagnostic ignored "-Wunused-parameter"
26 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
27 #elif defined(__GNUC__)
28 #pragma GCC diagnostic push
29 #pragma GCC diagnostic ignored "-Wshadow"
30 #pragma GCC diagnostic ignored "-Wunused-parameter"
31 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
32 #endif
33 
34 #include "llvm-c/Core.h"
35 #include "llvm-c/ExecutionEngine.h"
36 #include "llvm/ExecutionEngine/JITEventListener.h"
37 
38 #if defined(__clang__)
39 #pragma clang diagnostic pop
40 #elif defined(__GNUC__)
41 #pragma GCC diagnostic pop
42 #endif
43 
44 namespace panda::ecmascript::kungfu {
45 class CompilerLog;
46 class MethodLogList;
47 class LLVMModule;
48 
49 struct CodeInfo {
50     using sectionInfo = std::pair<uint8_t *, size_t>;
51     CodeInfo();
52 
53     ~CodeInfo();
54 
55     class CodeSpace {
56     public:
57         static CodeSpace *GetInstance();
58 
59         uint8_t *Alloca(uintptr_t size, bool isReq, size_t alignSize);
60 
61     private:
62         CodeSpace();
63         ~CodeSpace();
64 
65         static constexpr size_t REQUIRED_SECS_LIMIT = (1 << 29);  // 512M
66         static constexpr size_t UNREQUIRED_SECS_LIMIT = (1 << 28);  // 256M
67 
68         // start point of the buffer reserved for sections required in executing phase
69         uint8_t *reqSecs_ {nullptr};
70         size_t reqBufPos_ {0};
71         // start point of the buffer reserved for sections not required in executing phase
72         uint8_t *unreqSecs_ {nullptr};
73         size_t unreqBufPos_ {0};
74     };
75 
76     uint8_t *AllocaInReqSecBuffer(uintptr_t size, size_t alignSize = 0);
77 
78     uint8_t *AllocaInNotReqSecBuffer(uintptr_t size, size_t alignSize = 0);
79 
80     uint8_t *AllocaCodeSection(uintptr_t size, const char *sectionName);
81 
82     uint8_t *AllocaDataSection(uintptr_t size, const char *sectionName);
83 
84     void Reset();
85 
86     uint8_t *GetSectionAddr(ElfSecName sec) const;
87 
88     size_t GetSectionSize(ElfSecName sec) const;
89 
90     std::vector<std::pair<uint8_t *, uintptr_t>> GetCodeInfo() const;
91 
92     template <class Callback>
IterateSecInfosCodeInfo93     void IterateSecInfos(const Callback &cb) const
94     {
95         for (size_t i = 0; i < secInfos_.size(); i++) {
96             if (secInfos_[i].second == 0) {
97                 continue;
98             }
99             cb(i, secInfos_[i]);
100         }
101     }
102 
103 private:
104     std::array<sectionInfo, static_cast<int>(ElfSecName::SIZE)> secInfos_;
105     std::vector<std::pair<uint8_t *, uintptr_t>> codeInfo_ {}; // info for disasssembler, planed to be deprecated
106     bool alreadyPageAlign_ {false};
107 };
108 
109 enum class FPFlag : uint32_t {
110     ELIM_FP = 0,
111     RESERVE_FP = 1
112 };
113 
114 struct LOptions {
115     uint32_t optLevel : 2; // 2 bits for optimized level 0-4
116     uint32_t genFp : 1; // 1 bit for whether to generated frame pointer or not
117     uint32_t relocMode : 3; // 3 bits for relocation mode
118     // 3: default optLevel, 1: generating fp, 2: PIC mode
LOptionsLOptions119     LOptions() : optLevel(3), genFp(static_cast<uint32_t>(FPFlag::RESERVE_FP)), relocMode(2) {};
LOptionsLOptions120     LOptions(size_t level, FPFlag flag, size_t relocMode)
121         : optLevel(level), genFp(static_cast<uint32_t>(flag)), relocMode(relocMode) {};
122 };
123 
124 class LLVMAssembler {
125 public:
126     explicit LLVMAssembler(LLVMModule *lm, LOptions option = LOptions());
127     virtual ~LLVMAssembler();
128     void Run(const CompilerLog &log, bool fastCompileMode);
GetEngine()129     const LLVMExecutionEngineRef &GetEngine()
130     {
131         return engine_;
132     }
133     void Disassemble(const std::map<uintptr_t, std::string> &addr2name, uint64_t textOffset,
134                      const CompilerLog &log, const MethodLogList &logList, std::ostringstream &codeStream) const;
135     static void Disassemble(const std::map<uintptr_t, std::string> *addr2name,
136                             const std::string& triple, uint8_t *buf, size_t size);
137     static int GetFpDeltaPrevFramSp(LLVMValueRef fn, const CompilerLog &log);
138     static kungfu::CalleeRegAndOffsetVec GetCalleeReg2Offset(LLVMValueRef fn, const CompilerLog &log);
139 
GetSectionAddr(ElfSecName sec)140     uintptr_t GetSectionAddr(ElfSecName sec) const
141     {
142         return reinterpret_cast<uintptr_t>(codeInfo_.GetSectionAddr(sec));
143     }
144 
GetSectionSize(ElfSecName sec)145     uint32_t GetSectionSize(ElfSecName sec) const
146     {
147         return static_cast<uint32_t>(codeInfo_.GetSectionSize(sec));
148     }
149 
GetFuncPtrFromCompiledModule(LLVMValueRef function)150     void *GetFuncPtrFromCompiledModule(LLVMValueRef function)
151     {
152         return LLVMGetPointerToGlobal(engine_, function);
153     }
154 
155     template <class Callback>
IterateSecInfos(const Callback & cb)156     void IterateSecInfos(const Callback &cb) const
157     {
158         codeInfo_.IterateSecInfos(cb);
159     }
160 
SetObjFile(const llvm::object::ObjectFile * obj)161     void SetObjFile(const llvm::object::ObjectFile *obj)
162     {
163         objFile_ = obj;
164     }
165 private:
166     class AOTEventListener : public llvm::JITEventListener {
167       public:
AOTEventListener(LLVMAssembler * as)168         AOTEventListener(LLVMAssembler* as) : as_(as)
169         {
170         }
notifyObjectLoaded(ObjectKey key,const llvm::object::ObjectFile & objFile,const llvm::RuntimeDyld::LoadedObjectInfo & objInfo)171         void notifyObjectLoaded([[maybe_unused]] ObjectKey key, const llvm::object::ObjectFile &objFile,
172                                 [[maybe_unused]] const llvm::RuntimeDyld::LoadedObjectInfo &objInfo)
173         {
174             as_->SetObjFile(&objFile);
175         }
176       private:
GetAssembler()177         LLVMAssembler* GetAssembler() const
178         {
179             return as_;
180         }
181 
182         LLVMAssembler* as_ {nullptr};
183     };
184 
185     void UseRoundTripSectionMemoryManager();
186     bool BuildMCJITEngine();
187     void BuildAndRunPasses();
188     void BuildAndRunPassesFastMode();
189     void Initialize(LOptions option);
190     static void PrintInstAndStep(uint64_t &pc, uint8_t **byteSp, uintptr_t &numBytes, size_t instSize,
191                                  uint64_t textOffset, char *outString, std::ostringstream &codeStream,
192                                  bool logFlag = true);
193     uint64_t GetTextSectionIndex() const;
194 
195     LLVMMCJITCompilerOptions options_ {};
196     LLVMModule *llvmModule_ {nullptr};
197     LLVMModuleRef module_ {nullptr};
198     const llvm::object::ObjectFile* objFile_ {nullptr};
199     LLVMExecutionEngineRef engine_ {nullptr};
200     AOTEventListener listener_;
201     char *error_ {nullptr};
202     CodeInfo codeInfo_ {};
203 };
204 
205 class LLVMIRGeneratorImpl : public CodeGeneratorImpl {
206 public:
LLVMIRGeneratorImpl(LLVMModule * module,bool enableLog)207     LLVMIRGeneratorImpl(LLVMModule *module, bool enableLog)
208         : module_(module), enableLog_(enableLog) {}
209     ~LLVMIRGeneratorImpl() override = default;
210     void GenerateCodeForStub(Circuit *circuit, const ControlFlowGraph &graph, size_t index,
211                              const CompilationConfig *cfg) override;
212     void GenerateCode(Circuit *circuit, const ControlFlowGraph &graph, const CompilationConfig *cfg,
213         const MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile, const std::string &methodName) override;
214 
IsLogEnabled()215     bool IsLogEnabled() const
216     {
217         return enableLog_;
218     }
219 
220 private:
221     LLVMModule *module_;
222     bool enableLog_ {false};
223 };
224 }  // namespace panda::ecmascript::kungfu
225 #endif  // ECMASCRIPT_COMPILER_LLVM_CODEGEN_H
226