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 <sys/mman.h> 23 #include <vector> 24 25 #include "code_generator.h" 26 #include "ecmascript/compiler/llvm_ir_builder.h" 27 #include "ecmascript/ecma_macros.h" 28 #include "ecmascript/js_thread.h" 29 #include "ecmascript/stub_module.h" 30 #include "llvm-c/Analysis.h" 31 #include "llvm-c/Core.h" 32 #include "llvm-c/ExecutionEngine.h" 33 #include "llvm-c/Target.h" 34 #include "llvm-c/Transforms/PassManagerBuilder.h" 35 #include "llvm-c/Transforms/Scalar.h" 36 #include "llvm-c/Types.h" 37 #include "llvm/ExecutionEngine/Interpreter.h" 38 #include "llvm/ExecutionEngine/MCJIT.h" 39 #include "llvm/ExecutionEngine/SectionMemoryManager.h" 40 #include "llvm/IR/Instructions.h" 41 #include "llvm/Support/Host.h" 42 43 namespace panda::ecmascript::kungfu { 44 struct CodeInfo { 45 using ByteBuffer = std::vector<uint8_t>; 46 using BufferList = std::list<ByteBuffer>; 47 using StringList = std::list<std::string>; CodeInfoCodeInfo48 CodeInfo() 49 { 50 machineCode_ = static_cast<uint8_t *>(mmap(nullptr, MAX_MACHINE_CODE_SIZE, protRWX, flags, -1, 0)); 51 if (machineCode_ == reinterpret_cast<uint8_t *>(-1)) { 52 machineCode_ = nullptr; 53 } 54 if (machineCode_ != nullptr) { 55 ASAN_UNPOISON_MEMORY_REGION(machineCode_, MAX_MACHINE_CODE_SIZE); 56 } 57 } ~CodeInfoCodeInfo58 ~CodeInfo() 59 { 60 Reset(); 61 if (machineCode_ != nullptr) { 62 ASAN_POISON_MEMORY_REGION(machineCode_, MAX_MACHINE_CODE_SIZE); 63 munmap(machineCode_, MAX_MACHINE_CODE_SIZE); 64 } 65 machineCode_ = nullptr; 66 } 67 AllocaCodeSectionCodeInfo68 uint8_t *AllocaCodeSection(uintptr_t size, const char *sectionName) 69 { 70 uint8_t *addr = nullptr; 71 if (codeBufferPos_ + size > MAX_MACHINE_CODE_SIZE) { 72 LOG_ECMA(INFO) << std::hex << "AllocaCodeSection failed alloc codeBufferPos_:" << codeBufferPos_ 73 << " size:" << size << " larger MAX_MACHINE_CODE_SIZE:" << MAX_MACHINE_CODE_SIZE; 74 return nullptr; 75 } 76 LOG_ECMA(INFO) << "AllocaCodeSection size:" << size; 77 codeSectionNames_.push_back(sectionName); 78 addr = machineCode_ + codeBufferPos_; 79 codeInfo_.push_back({addr, size}); 80 codeBufferPos_ += size; 81 return addr; 82 } 83 AllocaDataSectionCodeInfo84 uint8_t *AllocaDataSection(uintptr_t size, const char *sectionName) 85 { 86 uint8_t *addr = nullptr; 87 dataSectionList_.push_back(std::vector<uint8_t>()); 88 dataSectionList_.back().resize(size); 89 dataSectionNames_.push_back(sectionName); 90 addr = static_cast<uint8_t *>(dataSectionList_.back().data()); 91 if (!strcmp(sectionName, ".llvm_stackmaps")) { 92 LOG_ECMA(INFO) << "llvm_stackmaps : " << addr << " size:" << size; 93 stackMapsSection_ = addr; 94 stackMapsSize_ = size; 95 } 96 return addr; 97 } 98 ResetCodeInfo99 void Reset() 100 { 101 stackMapsSection_ = nullptr; 102 codeInfo_.clear(); 103 dataSectionList_.clear(); 104 dataSectionNames_.clear(); 105 codeSectionNames_.clear(); 106 codeBufferPos_ = 0; 107 } 108 GetStackMapsSectionCodeInfo109 uint8_t *GetStackMapsSection() const 110 { 111 return stackMapsSection_; 112 } GetStackMapsSizeCodeInfo113 int GetStackMapsSize() const 114 { 115 return stackMapsSize_; 116 } GetCodeInfoCodeInfo117 std::vector<std::pair<uint8_t *, uintptr_t>> GetCodeInfo() const 118 { 119 return codeInfo_; 120 } 121 GetCodeSizeCodeInfo122 int GetCodeSize() const 123 { 124 return codeBufferPos_; 125 } 126 GetCodeBuffCodeInfo127 uint8_t *GetCodeBuff() const 128 { 129 return machineCode_; 130 } 131 132 private: 133 BufferList dataSectionList_ {}; 134 StringList dataSectionNames_ {}; 135 StringList codeSectionNames_ {}; 136 uint8_t *machineCode_ {nullptr}; 137 const size_t MAX_MACHINE_CODE_SIZE = (1 << 20); // 1M 138 static constexpr int protRWX = PROT_READ | PROT_WRITE | PROT_EXEC; // NOLINT(hicpp-signed-bitwise) 139 static constexpr int flags = MAP_ANONYMOUS | MAP_SHARED; // NOLINT(hicpp-signed-bitwise) 140 int codeBufferPos_ {0}; 141 /* <addr, size > for asssembler */ 142 std::vector<std::pair<uint8_t *, uintptr_t>> codeInfo_ {}; 143 /* stack map */ 144 uint8_t *stackMapsSection_ {nullptr}; 145 int stackMapsSize_ {0}; 146 }; 147 148 class LLVMAssembler { 149 public: 150 explicit LLVMAssembler(LLVMModuleRef module); 151 virtual ~LLVMAssembler(); 152 void Run(); GetEngine()153 const LLVMExecutionEngineRef &GetEngine() 154 { 155 return engine_; 156 } 157 void Disassemble(std::map<uint64_t, std::string> addr2name = std::map<uint64_t, std::string>()) const; GetStackMapsSection()158 uint8_t *GetStackMapsSection() const 159 { 160 return codeInfo_.GetStackMapsSection(); 161 } GetStackMapsSize()162 int GetStackMapsSize() const 163 { 164 return codeInfo_.GetStackMapsSize(); 165 } 166 GetCodeSize()167 int GetCodeSize() const 168 { 169 return codeInfo_.GetCodeSize(); 170 } GetCodeBuffer()171 uint8_t *GetCodeBuffer() const 172 { 173 return codeInfo_.GetCodeBuff(); 174 } 175 GetFuncPtrFromCompiledModule(LLVMValueRef function)176 void *GetFuncPtrFromCompiledModule(LLVMValueRef function) 177 { 178 return LLVMGetPointerToGlobal(engine_, function); 179 } 180 private: 181 void UseRoundTripSectionMemoryManager(); 182 bool BuildMCJITEngine(); 183 void BuildAndRunPasses(); 184 void BuildSimpleFunction(); 185 void FillPatchPointIDs(); 186 void RewritePatchPointIdOfStatePoint(LLVMValueRef instruction, uint64_t &callInsNum, uint64_t &funcNum); 187 void RewritePatchPointIdStoredOnThread(LLVMValueRef instruction, uint64_t id); 188 void Initialize(); 189 void InitMember(); 190 191 LLVMMCJITCompilerOptions options_ {}; 192 LLVMModuleRef module_; 193 LLVMExecutionEngineRef engine_ {nullptr}; 194 const CompilationConfig *compCfg_; 195 char *error_ {nullptr}; 196 struct CodeInfo codeInfo_ {}; 197 }; 198 199 class LLVMIRGeneratorImpl : public CodeGeneratorImpl { 200 public: LLVMIRGeneratorImpl(LLVMStubModule * module)201 explicit LLVMIRGeneratorImpl(LLVMStubModule *module) : module_(module) {} 202 ~LLVMIRGeneratorImpl() = default; 203 void GenerateCodeForStub(Circuit *circuit, const ControlFlowGraph &graph, int index, 204 const CompilationConfig *cfg) override; 205 206 private: 207 LLVMStubModule *module_; 208 }; 209 210 class LLVMModuleAssembler { 211 public: LLVMModuleAssembler(LLVMStubModule * module)212 explicit LLVMModuleAssembler(LLVMStubModule *module) 213 : stubmodule_(module), assembler_(module->GetModule()) {} 214 void AssembleModule(); 215 void AssembleStubModule(panda::ecmascript::StubModule *module); GetCodeSize()216 int GetCodeSize() const 217 { 218 return assembler_.GetCodeSize(); 219 } GetStackMapsSize()220 int GetStackMapsSize() const 221 { 222 return assembler_.GetStackMapsSize(); 223 } CopyAssemblerToCode(panda::ecmascript::MachineCode * code)224 void CopyAssemblerToCode(panda::ecmascript::MachineCode *code) 225 { 226 code->SetData(reinterpret_cast<uint8_t *>(assembler_.GetCodeBuffer()), assembler_.GetCodeSize()); 227 } 228 private: 229 LLVMStubModule *stubmodule_; 230 LLVMAssembler assembler_; 231 }; 232 } // namespace panda::ecmascript::kungfu 233 #endif // ECMASCRIPT_COMPILER_LLVM_CODEGEN_H 234