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