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