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_FILE_GENERATORS_H 17 #define ECMASCRIPT_COMPILER_FILE_GENERATORS_H 18 19 #include <tuple> 20 21 #include "ecmascript/compiler/assembler_module.h" 22 #include "ecmascript/compiler/compiler_log.h" 23 #include "ecmascript/compiler/llvm_codegen.h" 24 #include "ecmascript/compiler/llvm_ir_builder.h" 25 #include "ecmascript/compiler/bytecode_info_collector.h" 26 #include "ecmascript/compiler/bytecode_circuit_builder.h" 27 #include "ecmascript/ecma_vm.h" 28 #include "ecmascript/aot_file_manager.h" 29 #include "ecmascript/jspandafile/js_pandafile.h" 30 31 namespace panda::ecmascript::kungfu { 32 class Module { 33 public: 34 Module() = default; Module(LLVMModule * module,LLVMAssembler * assembler)35 Module(LLVMModule *module, LLVMAssembler *assembler) 36 : llvmModule_(module), assembler_(assembler) 37 { 38 } 39 CollectFuncEntryInfo(std::map<uintptr_t,std::string> & addr2name,StubFileInfo & stubInfo,uint32_t moduleIndex,const CompilerLog & log)40 void CollectFuncEntryInfo(std::map<uintptr_t, std::string> &addr2name, StubFileInfo &stubInfo, 41 uint32_t moduleIndex, const CompilerLog &log) 42 { 43 auto engine = assembler_->GetEngine(); 44 auto callSigns = llvmModule_->GetCSigns(); 45 std::map<uintptr_t, int> addr2FpToPrevFrameSpDelta; 46 std::vector<uint64_t> funSizeVec; 47 std::vector<uintptr_t> entrys; 48 for (size_t j = 0; j < llvmModule_->GetFuncCount(); j++) { 49 LLVMValueRef func = llvmModule_->GetFunction(j); 50 ASSERT(func != nullptr); 51 uintptr_t entry = reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(engine, func)); 52 entrys.push_back(entry); 53 } 54 auto codeBuff = assembler_->GetSectionAddr(ElfSecName::TEXT); 55 const size_t funcCount = llvmModule_->GetFuncCount(); 56 funcCount_ = funcCount; 57 startIndex_ = stubInfo.GetEntrySize(); 58 for (size_t j = 0; j < funcCount; j++) { 59 auto cs = callSigns[j]; 60 LLVMValueRef func = llvmModule_->GetFunction(j); 61 ASSERT(func != nullptr); 62 int delta = assembler_->GetFpDeltaPrevFramSp(func, log); 63 ASSERT(delta >= 0 && (delta % sizeof(uintptr_t) == 0)); 64 uint32_t funcSize = 0; 65 if (j < funcCount - 1) { 66 funcSize = entrys[j + 1] - entrys[j]; 67 } else { 68 funcSize = codeBuff + assembler_->GetSectionSize(ElfSecName::TEXT) - entrys[j]; 69 } 70 kungfu::CalleeRegAndOffsetVec info = assembler_->GetCalleeReg2Offset(func, log); 71 stubInfo.AddEntry(cs->GetTargetKind(), false, cs->GetID(), entrys[j] - codeBuff, moduleIndex, delta, 72 funcSize, info); 73 ASSERT(!cs->GetName().empty()); 74 addr2name[entrys[j]] = cs->GetName(); 75 } 76 } 77 CollectFuncEntryInfo(std::map<uintptr_t,std::string> & addr2name,AnFileInfo & aotInfo,uint32_t moduleIndex,const CompilerLog & log)78 void CollectFuncEntryInfo(std::map<uintptr_t, std::string> &addr2name, AnFileInfo &aotInfo, 79 uint32_t moduleIndex, const CompilerLog &log) 80 { 81 auto engine = assembler_->GetEngine(); 82 std::vector<std::tuple<uint64_t, size_t, int>> funcInfo; // entry idx delta 83 std::vector<kungfu::CalleeRegAndOffsetVec> calleeSaveRegisters; // entry idx delta 84 llvmModule_->IteratefuncIndexMap([&](size_t idx, LLVMValueRef func) { 85 uint64_t funcEntry = reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(engine, func)); 86 uint64_t length = 0; 87 std::string funcName(LLVMGetValueName2(func, reinterpret_cast<size_t *>(&length))); 88 ASSERT(length != 0); 89 addr2name[funcEntry] = funcName; 90 int delta = assembler_->GetFpDeltaPrevFramSp(func, log); 91 ASSERT(delta >= 0 && (delta % sizeof(uintptr_t) == 0)); 92 funcInfo.emplace_back(std::tuple(funcEntry, idx, delta)); 93 kungfu::CalleeRegAndOffsetVec info = assembler_->GetCalleeReg2Offset(func, log); 94 calleeSaveRegisters.emplace_back(info); 95 }); 96 auto codeBuff = assembler_->GetSectionAddr(ElfSecName::TEXT); 97 const size_t funcCount = funcInfo.size(); 98 funcCount_ = funcCount; 99 startIndex_ = aotInfo.GetEntrySize(); 100 for (size_t i = 0; i < funcInfo.size(); i++) { 101 uint64_t funcEntry; 102 size_t idx; 103 int delta; 104 uint32_t funcSize; 105 std::tie(funcEntry, idx, delta) = funcInfo[i]; 106 if (i < funcCount - 1) { 107 funcSize = std::get<0>(funcInfo[i + 1]) - funcEntry; 108 } else { 109 funcSize = codeBuff + assembler_->GetSectionSize(ElfSecName::TEXT) - funcEntry; 110 } 111 auto found = addr2name[funcEntry].find(panda::ecmascript::JSPandaFile::ENTRY_FUNCTION_NAME); 112 bool isMainFunc = found != std::string::npos; 113 aotInfo.AddEntry(CallSignature::TargetKind::JSFUNCTION, isMainFunc, idx, 114 funcEntry - codeBuff, moduleIndex, delta, funcSize, calleeSaveRegisters[i]); 115 } 116 } 117 IsRelaSection(ElfSecName sec)118 bool IsRelaSection(ElfSecName sec) const 119 { 120 return sec == ElfSecName::RELATEXT || sec == ElfSecName::STRTAB || sec == ElfSecName::SYMTAB; 121 } 122 123 void CollectModuleSectionDes(ModuleSectionDes &moduleDes, bool stub = false) const 124 { 125 ASSERT(assembler_ != nullptr); 126 assembler_->IterateSecInfos([&](size_t i, std::pair<uint8_t *, size_t> secInfo) { 127 auto curSec = ElfSection(i); 128 ElfSecName sec = curSec.GetElfEnumValue(); 129 if (stub && IsRelaSection(sec)) { 130 moduleDes.EraseSec(sec); 131 } else { // aot need relocated; stub don't need collect relocated section 132 moduleDes.SetSecAddr(reinterpret_cast<uint64_t>(secInfo.first), sec); 133 moduleDes.SetSecSize(secInfo.second, sec); 134 moduleDes.SetStartIndex(startIndex_); 135 moduleDes.SetFuncCount(funcCount_); 136 } 137 }); 138 CollectStackMapDes(moduleDes); 139 } 140 141 void CollectStackMapDes(ModuleSectionDes &moduleDes) const; 142 GetCompilationConfig()143 const CompilationConfig *GetCompilationConfig() 144 { 145 return llvmModule_->GetCompilationConfig(); 146 } 147 GetSectionSize(ElfSecName sec)148 uint32_t GetSectionSize(ElfSecName sec) const 149 { 150 return assembler_->GetSectionSize(sec); 151 } 152 GetSectionAddr(ElfSecName sec)153 uintptr_t GetSectionAddr(ElfSecName sec) const 154 { 155 return assembler_->GetSectionAddr(sec); 156 } 157 RunAssembler(const CompilerLog & log)158 void RunAssembler(const CompilerLog &log) 159 { 160 assembler_->Run(log); 161 } 162 DisassemblerFunc(std::map<uintptr_t,std::string> & addr2name,const CompilerLog & log,const MethodLogList & logList)163 void DisassemblerFunc(std::map<uintptr_t, std::string> &addr2name, 164 const CompilerLog &log, const MethodLogList &logList) 165 { 166 assembler_->Disassemble(addr2name, log, logList); 167 } 168 DestoryModule()169 void DestoryModule() 170 { 171 if (llvmModule_ != nullptr) { 172 delete llvmModule_; 173 llvmModule_ = nullptr; 174 } 175 if (assembler_ != nullptr) { 176 delete assembler_; 177 assembler_ = nullptr; 178 } 179 } 180 private: 181 LLVMModule *llvmModule_ {nullptr}; 182 LLVMAssembler *assembler_ {nullptr}; 183 // record current module first function index in StubFileInfo/AnFileInfo 184 uint32_t startIndex_ {static_cast<uint32_t>(-1)}; 185 uint32_t funcCount_ {0}; 186 }; 187 188 class FileGenerator { 189 public: FileGenerator(const CompilerLog * log,const MethodLogList * logList)190 FileGenerator(const CompilerLog *log, const MethodLogList *logList) : log_(log), logList_(logList) {}; 191 virtual ~FileGenerator() = default; 192 GetLog()193 const CompilerLog GetLog() const 194 { 195 return *log_; 196 } 197 protected: 198 std::vector<Module> modulePackage_ {}; 199 const CompilerLog *log_ {nullptr}; 200 const MethodLogList *logList_ {nullptr}; 201 RunLLVMAssembler()202 void RunLLVMAssembler() 203 { 204 for (auto m : modulePackage_) { 205 m.RunAssembler(*(log_)); 206 } 207 } 208 DisassembleEachFunc(std::map<uintptr_t,std::string> & addr2name)209 void DisassembleEachFunc(std::map<uintptr_t, std::string> &addr2name) 210 { 211 for (auto m : modulePackage_) { 212 m.DisassemblerFunc(addr2name, *(log_), *(logList_)); 213 } 214 } 215 DestoryModule()216 void DestoryModule() 217 { 218 for (auto m : modulePackage_) { 219 m.DestoryModule(); 220 } 221 } 222 223 void CollectStackMapDes(ModuleSectionDes& des); 224 }; 225 226 class AOTFileGenerator : public FileGenerator { 227 public: AOTFileGenerator(const CompilerLog * log,const MethodLogList * logList,EcmaVM * vm,const std::string & triple)228 AOTFileGenerator(const CompilerLog *log, const MethodLogList *logList, EcmaVM* vm, const std::string &triple) 229 : FileGenerator(log, logList), vm_(vm), cfg_(triple) {} 230 231 ~AOTFileGenerator() override = default; 232 AddModule(LLVMModule * llvmModule,LLVMAssembler * assembler,BytecodeInfoCollector * bcInfoCollector)233 void AddModule(LLVMModule *llvmModule, LLVMAssembler *assembler, BytecodeInfoCollector *bcInfoCollector) 234 { 235 vm_->GetTSManager()->ProcessSnapshotConstantPool(bcInfoCollector); 236 modulePackage_.emplace_back(Module(llvmModule, assembler)); 237 } 238 GenerateMethodToEntryIndexMap()239 void GenerateMethodToEntryIndexMap() 240 { 241 const std::vector<AOTFileInfo::FuncEntryDes> &entries = aotInfo_.GetStubs(); 242 uint32_t entriesSize = entries.size(); 243 for (uint32_t i = 0; i < entriesSize; ++i) { 244 const AOTFileInfo::FuncEntryDes &entry = entries[i]; 245 methodToEntryIndexMap_[entry.indexInKindOrMethodId_] = i; 246 } 247 } 248 249 // save function for aot files containing normal func translated from JS/TS 250 void SaveAOTFile(const std::string &filename); 251 void SaveSnapshotFile(); 252 private: 253 AnFileInfo aotInfo_; 254 EcmaVM* vm_; 255 CompilationConfig cfg_; 256 // MethodID->EntryIndex 257 std::map<uint32_t, uint32_t> methodToEntryIndexMap_ {}; 258 259 // collect aot component info 260 void CollectCodeInfo(); 261 }; 262 263 class StubFileGenerator : public FileGenerator { 264 public: StubFileGenerator(const CompilerLog * log,const MethodLogList * logList,const std::string & triple,bool enablePGOProfiler)265 StubFileGenerator(const CompilerLog *log, const MethodLogList *logList, const std::string &triple, 266 bool enablePGOProfiler) : FileGenerator(log, logList), cfg_(triple, enablePGOProfiler) {}; 267 ~StubFileGenerator() override = default; AddModule(LLVMModule * llvmModule,LLVMAssembler * assembler)268 void AddModule(LLVMModule *llvmModule, LLVMAssembler *assembler) 269 { 270 modulePackage_.emplace_back(Module(llvmModule, assembler)); 271 } 272 // save function funcs for aot files containing stubs 273 void SaveStubFile(const std::string &filename); 274 private: 275 StubFileInfo stubInfo_; 276 AssemblerModule asmModule_; 277 CompilationConfig cfg_; 278 279 void RunAsmAssembler(); 280 void CollectAsmStubCodeInfo(std::map<uintptr_t, std::string> &addr2name, uint32_t bridgeModuleIdx); 281 void CollectCodeInfo(); 282 }; 283 } // namespace panda::ecmascript::kungfu 284 #endif // ECMASCRIPT_COMPILER_FILE_GENERATORS_H 285