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
23namespace panda::ecmascript::kungfu {
24using ControlFlowGraph = std::vector<std::vector<GateRef>>;
25class CompilationConfig;
26class CompilerLog;
27
28struct 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>
122    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
132private:
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
142class Assembler {
143public:
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
149    uintptr_t GetSectionAddr(ElfSecName sec) const
150    {
151        return reinterpret_cast<uintptr_t>(codeInfo_.GetSectionAddr(sec));
152    }
153
154    uint32_t GetSectionSize(ElfSecName sec) const
155    {
156        return static_cast<uint32_t>(codeInfo_.GetSectionSize(sec));
157    }
158
159    template <class Callback>
160    void IterateSecInfos(const Callback &cb) const
161    {
162        codeInfo_.IterateSecInfos(cb);
163    }
164
165    const CodeInfo &GetCodeInfo() const
166    {
167        return codeInfo_;
168    }
169protected:
170    CodeInfo codeInfo_;
171};
172
173class CodeGeneratorImpl {
174public:
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
188class CodeGenerator {
189public:
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
197    void RunForStub(Circuit *circuit, const ControlFlowGraph &graph, size_t index, const CompilationConfig *cfg)
198    {
199        impl_->GenerateCodeForStub(circuit, graph, index, cfg);
200    }
201
202    const std::string& GetMethodName() const
203    {
204        return methodName_;
205    }
206
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
215private:
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