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