• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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