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