• 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 <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