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_CODE_GENERATOR_H
17 #define ECMASCRIPT_COMPILER_CODE_GENERATOR_H
18 
19 #include "ecmascript/compiler/circuit.h"
20 #include "ecmascript/compiler/binary_section.h"
21 #include "ecmascript/jspandafile/method_literal.h"
22 
23 namespace panda::ecmascript::kungfu {
24 using ControlFlowGraph = std::vector<std::vector<GateRef>>;
25 class CompilationConfig;
26 class CompilerLog;
27 
28 struct CodeInfo {
29     using sectionInfo = std::pair<uint8_t *, size_t>;
30     typedef uint8_t *(CodeInfo::*AllocaSectionCallback)(uintptr_t size, size_t alignSize);
31 
32     class CodeSpace {
33     public:
34         static CodeSpace *GetInstance();
35 
36         uint8_t *Alloca(uintptr_t size, bool isReq, size_t alignSize);
37 
38     private:
39         CodeSpace();
40         ~CodeSpace();
41 
42         static constexpr size_t REQUIRED_SECS_LIMIT = (1 << 29);  // 512M
43         static constexpr size_t UNREQUIRED_SECS_LIMIT = (1 << 28);  // 256M
44 
45         // start point of the buffer reserved for sections required in executing phase
46         uint8_t *reqSecs_ {nullptr};
47         size_t reqBufPos_ {0};
48         // start point of the buffer reserved for sections not required in executing phase
49         uint8_t *unreqSecs_ {nullptr};
50         size_t unreqBufPos_ {0};
51     };
52 
53     class CodeSpaceOnDemand {
54     public:
55         CodeSpaceOnDemand() = default;
56 
57         uint8_t *Alloca(uintptr_t size, bool isReq, size_t alignSize);
58 
59         ~CodeSpaceOnDemand();
60 
61     private:
62         static constexpr size_t SECTION_LIMIT = (1 << 29);  // 512M
63 
64         // record all memory blocks requested.
65         std::vector<std::pair<uint8_t *, uintptr_t>> sections_;
66     };
67 
68     struct FuncInfo {
69         uint32_t addr = 0;
70         int32_t fp2PrevFrameSpDelta = 0;
71         kungfu::CalleeRegAndOffsetVec calleeRegInfo;
72     };
73 
74     CodeInfo(CodeSpaceOnDemand &codeSpaceOnDemand);
75 
76     ~CodeInfo();
77 
78     uint8_t *AllocaOnDemand(uintptr_t size, size_t alignSize = 0);
79 
80     uint8_t *AllocaInReqSecBuffer(uintptr_t size, size_t alignSize = 0);
81 
82     uint8_t *AllocaInNotReqSecBuffer(uintptr_t size, size_t alignSize = 0);
83 
84     uint8_t *AllocaCodeSectionImp(uintptr_t size, const char *sectionName, AllocaSectionCallback allocaInReqSecBuffer);
85 
86     uint8_t *AllocaCodeSection(uintptr_t size, const char *sectionName);
87 
88     uint8_t *AllocaCodeSectionOnDemand(uintptr_t size, const char *sectionName);
89 
90     uint8_t *AllocaDataSectionImp(uintptr_t size, const char *sectionName, AllocaSectionCallback allocaInReqSecBuffer,
91                                   AllocaSectionCallback allocaInNotReqSecBuffer);
92 
93     uint8_t *AllocaDataSection(uintptr_t size, const char *sectionName);
94 
95     uint8_t *AllocaDataSectionOnDemand(uintptr_t size, const char *sectionName);
96 
97     void SaveFunc2Addr(std::string funcName, uint32_t address);
98 
99     void SaveFunc2FPtoPrevSPDelta(std::string funcName, int32_t fp2PrevSpDelta);
100 
101     void SaveFunc2CalleeOffsetInfo(std::string funcName, kungfu::CalleeRegAndOffsetVec calleeRegInfo);
102 
103     void SavePC2DeoptInfo(uint64_t pc, std::vector<uint8_t> pc2DeoptInfo);
104 
105     void SavePC2CallSiteInfo(uint64_t pc, std::vector<uint8_t> callSiteInfo);
106 
107     const std::map<std::string, FuncInfo> &GetFuncInfos() const;
108 
109     const std::map<uint64_t, std::vector<uint8_t>> &GetPC2DeoptInfo() const;
110 
111     const std::unordered_map<uint64_t, std::vector<uint8_t>> &GetPC2CallsiteInfo() const;
112 
113     void Reset();
114 
115     uint8_t *GetSectionAddr(ElfSecName sec) const;
116 
117     size_t GetSectionSize(ElfSecName sec) const;
118 
119     std::vector<std::pair<uint8_t *, uintptr_t>> GetCodeInfo() const;
120 
121     template <class Callback>
IterateSecInfospanda::ecmascript::kungfu::CodeInfo122     void IterateSecInfos(const Callback &cb) const
123     {
124         for (size_t i = 0; i < secInfos_.size(); i++) {
125             if (secInfos_[i].second == 0) {
126                 continue;
127             }
128             cb(i, secInfos_[i]);
129         }
130     }
131 
132 private:
133     std::array<sectionInfo, static_cast<int>(ElfSecName::SIZE)> secInfos_;
134     std::vector<std::pair<uint8_t *, uintptr_t>> codeInfo_ {}; // info for disasssembler, planed to be deprecated
135     std::map<std::string, FuncInfo> func2FuncInfo;
136     std::map<uint64_t, std::vector<uint8_t>> pc2DeoptInfo;
137     std::unordered_map<uint64_t, std::vector<uint8_t>> pc2CallsiteInfo;
138     bool alreadyPageAlign_ {false};
139     CodeSpaceOnDemand &codeSpaceOnDemand_;
140 };
141 
142 class Assembler {
143 public:
Assembler(CodeInfo::CodeSpaceOnDemand &codeSpaceOnDemand)144     explicit Assembler(CodeInfo::CodeSpaceOnDemand &codeSpaceOnDemand) : codeInfo_(codeSpaceOnDemand)
145     {}
146     virtual ~Assembler() = default;
147     virtual void Run(const CompilerLog &log, bool fastCompileMode, bool isJit = false) = 0;
148 
GetSectionAddr(ElfSecName sec) const149     uintptr_t GetSectionAddr(ElfSecName sec) const
150     {
151         return reinterpret_cast<uintptr_t>(codeInfo_.GetSectionAddr(sec));
152     }
153 
GetSectionSize(ElfSecName sec) const154     uint32_t GetSectionSize(ElfSecName sec) const
155     {
156         return static_cast<uint32_t>(codeInfo_.GetSectionSize(sec));
157     }
158 
159     template <class Callback>
IterateSecInfos(const Callback &cb) const160     void IterateSecInfos(const Callback &cb) const
161     {
162         codeInfo_.IterateSecInfos(cb);
163     }
164 
GetCodeInfo() const165     const CodeInfo &GetCodeInfo() const
166     {
167         return codeInfo_;
168     }
169 protected:
170     CodeInfo codeInfo_;
171 };
172 
173 class CodeGeneratorImpl {
174 public:
175     CodeGeneratorImpl() = default;
176 
177     virtual ~CodeGeneratorImpl() = default;
178 
179     virtual void GenerateCodeForStub(Circuit *circuit, const ControlFlowGraph &graph, size_t index,
180                                      const CompilationConfig *cfg) = 0;
181 
182     virtual void GenerateCode(Circuit *circuit, const ControlFlowGraph &graph, const CompilationConfig *cfg,
183                               const MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile,
184                               const std::string &methodName, const FrameType frameType,
185                               bool enableOptInlining, bool enableBranchProfiling) = 0;
186 };
187 
188 class CodeGenerator {
189 public:
CodeGenerator(std::unique_ptr<CodeGeneratorImpl> &impl, const std::string& methodName)190     CodeGenerator(std::unique_ptr<CodeGeneratorImpl> &impl, const std::string& methodName)
191         : impl_(std::move(impl)), methodName_(methodName)
192     {
193     }
194 
195     ~CodeGenerator() = default;
196 
RunForStub(Circuit *circuit, const ControlFlowGraph &graph, size_t index, const CompilationConfig *cfg)197     void RunForStub(Circuit *circuit, const ControlFlowGraph &graph, size_t index, const CompilationConfig *cfg)
198     {
199         impl_->GenerateCodeForStub(circuit, graph, index, cfg);
200     }
201 
GetMethodName() const202     const std::string& GetMethodName() const
203     {
204         return methodName_;
205     }
206 
Run(Circuit *circuit, const ControlFlowGraph &graph, const CompilationConfig *cfg, const MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile, const FrameType frameType, bool enableOptInlining, bool enableOptBranchProfiling)207     void Run(Circuit *circuit, const ControlFlowGraph &graph, const CompilationConfig *cfg,
208              const MethodLiteral *methodLiteral, const JSPandaFile *jsPandaFile, const FrameType frameType,
209              bool enableOptInlining, bool enableOptBranchProfiling)
210     {
211         impl_->GenerateCode(circuit, graph, cfg, methodLiteral, jsPandaFile, methodName_, frameType,
212             enableOptInlining, enableOptBranchProfiling);
213     }
214 
215 private:
216     std::unique_ptr<CodeGeneratorImpl> impl_{nullptr};
217     std::string methodName_;
218 };
219 } // namespace panda::ecmascript::kungfu
220 #endif // ECMASCRIPT_COMPILER_CODE_GENERATOR_H
221