• 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 #include "ecmascript/compiler/file_generators.h"
17 
18 #include "ecmascript/compiler/pgo_type/pgo_type_manager.h"
19 #include "ecmascript/platform/code_sign.h"
20 #include "ecmascript/platform/directory.h"
21 #include "ecmascript/platform/os.h"
22 #include "ecmascript/snapshot/mem/snapshot.h"
23 #include "ecmascript/stackmap/llvm/llvm_stackmap_parser.h"
24 #ifdef COMPILE_MAPLE
25 #include "ecmascript/compiler/codegen/maple/litecg_codegen.h"
26 #include "ecmascript/compiler/codegen/maple/litecg_ir_builder.h"
27 #include "ecmascript/compiler/codegen/maple/maple_be/include/litecg/litecg.h"
28 #include "ecmascript/stackmap/litecg/litecg_stackmap_type.h"
29 #ifdef JIT_ENABLE_CODE_SIGN
30 #include "ecmascript/compiler/jit_signcode.h"
31 #endif
32 #endif
33 #include "ecmascript/compiler/jit_compiler.h"
34 
35 namespace panda::ecmascript::kungfu {
CollectStackMapDes(ModuleSectionDes & des) const36 void Module::CollectStackMapDes(ModuleSectionDes& des) const
37 {
38     uint32_t stackmapSize = des.GetSecSize(ElfSecName::LLVM_STACKMAP);
39     std::unique_ptr<uint8_t[]> stackmapPtr(std::make_unique<uint8_t[]>(stackmapSize));
40     uint64_t addr = des.GetSecAddr(ElfSecName::LLVM_STACKMAP);
41     if (addr == 0) { // assembler stub don't existed llvm stackmap
42         return;
43     }
44     uint64_t textAddr = des.GetSecAddr(ElfSecName::TEXT);
45     if (memcpy_s(stackmapPtr.get(), stackmapSize, reinterpret_cast<void *>(addr), stackmapSize) != EOK) {
46         LOG_COMPILER(FATAL) << "memcpy_s failed";
47         UNREACHABLE();
48     }
49     std::shared_ptr<uint8_t> ptr = nullptr;
50     uint32_t size = 0;
51     ArkStackMapBuilder builder;
52     std::tie(ptr, size) = builder.Run(std::move(stackmapPtr), textAddr, irModule_->GetTriple());
53     des.EraseSec(ElfSecName::LLVM_STACKMAP);
54     des.SetArkStackMapPtr(ptr);
55     des.SetArkStackMapSize(size);
56 }
57 
CollectAnStackMapDes(ModuleSectionDes & des,uint64_t textOffset,CGStackMapInfo & stackMapInfo) const58 void Module::CollectAnStackMapDes(ModuleSectionDes& des, uint64_t textOffset,
59                                   CGStackMapInfo &stackMapInfo) const
60 {
61 #ifdef COMPILE_MAPLE
62     if (!IsLLVM()) {
63         static_cast<LiteCGAssembler*>(assembler_)->CollectAnStackMap(stackMapInfo);
64         return;
65     }
66 #endif
67     uint32_t stackmapSize = des.GetSecSize(ElfSecName::LLVM_STACKMAP);
68     std::unique_ptr<uint8_t[]> stackmapPtr(std::make_unique<uint8_t[]>(stackmapSize));
69     uint64_t addr = des.GetSecAddr(ElfSecName::LLVM_STACKMAP);
70     if (addr == 0) { // assembler stub don't existed llvm stackmap
71         return;
72     }
73     uint64_t textAddr = des.GetSecAddr(ElfSecName::TEXT);
74     if (memcpy_s(stackmapPtr.get(), stackmapSize, reinterpret_cast<void *>(addr), stackmapSize) != EOK) {
75         LOG_COMPILER(FATAL) << "memcpy_s failed";
76         UNREACHABLE();
77     }
78     ArkStackMapBuilder builder;
79     builder.Collect(std::move(stackmapPtr), textAddr, textOffset, stackMapInfo);
80     des.EraseSec(ElfSecName::LLVM_STACKMAP);
81 }
82 
GetFuncEntryPoints()83 std::vector<uintptr_t> Module::GetFuncEntryPoints()
84 {
85     std::vector<uintptr_t> entrys;
86     if (irModule_->GetModuleKind() != MODULE_LLVM) {
87         std::cout << "GetFuncEntryPoints is not supported for litecg currently" << std::endl;
88         return entrys;
89     }
90     LLVMModule *llvmModule = static_cast<LLVMModule *>(irModule_);
91     LLVMAssembler *assembler = static_cast<LLVMAssembler *>(assembler_);
92     auto engine = assembler->GetEngine();
93 
94     for (size_t j = 0; j < llvmModule->GetFuncCount(); j++) {
95         LLVMValueRef func = llvmModule->GetFunction(j);
96         ASSERT(func != nullptr);
97         uintptr_t entry = reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(engine, func));
98         entrys.push_back(entry);
99     }
100     return entrys;
101 }
102 
CollectFuncEntryInfo(const std::vector<uintptr_t> & entrys,std::map<uintptr_t,std::string> & addr2name,StubFileInfo & stubInfo,uint32_t moduleIndex,const CompilerLog & log)103 void Module::CollectFuncEntryInfo(const std::vector<uintptr_t>& entrys, std::map<uintptr_t, std::string> &addr2name,
104                                   StubFileInfo &stubInfo, uint32_t moduleIndex, const CompilerLog &log)
105 {
106     LLVMModule *llvmModule = static_cast<LLVMModule*>(irModule_);
107     LLVMAssembler *assembler = static_cast<LLVMAssembler*>(assembler_);
108     auto codeBuff = assembler->GetSectionAddr(ElfSecName::TEXT);
109     auto callSigns = llvmModule->GetCSigns();
110     const size_t funcCount = entrys.size();
111     funcCount_ = funcCount;
112     startIndex_ = stubInfo.GetEntrySize();
113 
114     for (size_t j = 0; j < funcCount; j++) {
115         auto cs = callSigns[j];
116         LLVMValueRef func = llvmModule->GetFunction(j);
117         ASSERT(func != nullptr);
118         int delta = assembler->GetFpDeltaPrevFramSp(func, log);
119         ASSERT(delta >= 0 && (delta % sizeof(uintptr_t) == 0));
120         uint32_t funcSize = 0;
121         if (j < funcCount - 1) {
122             funcSize = entrys[j + 1] - entrys[j];
123         } else {
124             funcSize = codeBuff + assembler->GetSectionSize(ElfSecName::TEXT) - entrys[j];
125         }
126         kungfu::CalleeRegAndOffsetVec info = assembler->GetCalleeReg2Offset(func, log);
127         stubInfo.AddEntry(cs->GetTargetKind(), false, false, cs->GetID(), entrys[j] - codeBuff,
128                           AOTFileManager::STUB_FILE_INDEX, moduleIndex, delta, funcSize, info);
129         ASSERT(!cs->GetName().empty());
130         addr2name[entrys[j]] = cs->GetName();
131     }
132 }
133 
CollectFuncEntryInfo(std::map<uintptr_t,std::string> & addr2name,AnFileInfo & aotInfo,uint32_t fileIndex,uint32_t moduleIndex,const CompilerLog & log)134 void Module::CollectFuncEntryInfo(std::map<uintptr_t, std::string> &addr2name, AnFileInfo &aotInfo, uint32_t fileIndex,
135                                   uint32_t moduleIndex, const CompilerLog &log)
136 {
137 #ifdef COMPILE_MAPLE
138     if (irModule_->GetModuleKind() != MODULE_LLVM) {
139         CollectFuncEntryInfoByLiteCG(addr2name, aotInfo, fileIndex, moduleIndex);
140         return;
141     }
142 #endif
143     LLVMAssembler *assembler = static_cast<LLVMAssembler*>(assembler_);
144     auto engine = assembler->GetEngine();
145     std::vector<std::tuple<uint64_t, size_t, int, bool>> funcInfo; // entry idx delta
146     std::vector<kungfu::CalleeRegAndOffsetVec> calleeSaveRegisters; // entry idx delta
147     // 1.Compile all functions and collect function infos
148     LLVMModule *llvmModule = static_cast<LLVMModule*>(irModule_);
149     llvmModule->IteratefuncIndexMap([&](size_t idx, LLVMValueRef func, bool isFastCall) {
150         uint64_t funcEntry = reinterpret_cast<uintptr_t>(LLVMGetPointerToGlobal(engine, func));
151         uint64_t length = 0;
152         std::string funcName(LLVMGetValueName2(func, reinterpret_cast<size_t *>(&length)));
153         ASSERT(length != 0);
154         addr2name[funcEntry] = funcName;
155         int delta = assembler->GetFpDeltaPrevFramSp(func, log);
156         ASSERT(delta >= 0 && (delta % sizeof(uintptr_t) == 0));
157         funcInfo.emplace_back(std::tuple(funcEntry, idx, delta, isFastCall));
158         kungfu::CalleeRegAndOffsetVec info = assembler->GetCalleeReg2Offset(func, log);
159         calleeSaveRegisters.emplace_back(info);
160     });
161     // 2.After all functions compiled, the module sections would be fixed
162     uintptr_t textAddr = GetTextAddr();
163     uint32_t textSize = GetTextSize();
164     uintptr_t rodataAddrBeforeText = 0;
165     uint32_t rodataSizeBeforeText = 0;
166     uintptr_t rodataAddrAfterText = 0;
167     uint32_t rodataSizeAfterText = 0;
168     std::tie(rodataAddrBeforeText, rodataSizeBeforeText, rodataAddrAfterText, rodataSizeAfterText) =
169         GetMergedRODataAddrAndSize(textAddr);
170     aotInfo.AlignTextSec(AOTFileInfo::PAGE_ALIGN);
171     if (rodataSizeBeforeText != 0) {
172         aotInfo.UpdateCurTextSecOffset(rodataSizeBeforeText);
173         aotInfo.AlignTextSec(AOTFileInfo::TEXT_SEC_ALIGN);
174     }
175 
176     const size_t funcCount = funcInfo.size();
177     funcCount_ = funcCount;
178     startIndex_ = aotInfo.GetEntrySize();
179     // 3.Add function entries based on the module sections
180     for (size_t i = 0; i < funcInfo.size(); i++) {
181         uint64_t funcEntry;
182         size_t idx;
183         int delta;
184         bool isFastCall;
185         uint32_t funcSize;
186         std::tie(funcEntry, idx, delta, isFastCall) = funcInfo[i];
187         if (i < funcCount - 1) {
188             funcSize = std::get<0>(funcInfo[i + 1]) - funcEntry;
189         } else {
190             funcSize = textAddr + textSize - funcEntry;
191         }
192         auto found = addr2name[funcEntry].find(panda::ecmascript::JSPandaFile::ENTRY_FUNCTION_NAME);
193         bool isMainFunc = found != std::string::npos;
194         uint64_t offset = funcEntry - textAddr + aotInfo.GetCurTextSecOffset();
195         aotInfo.AddEntry(CallSignature::TargetKind::JSFUNCTION, isMainFunc, isFastCall, idx,
196                          offset, fileIndex, moduleIndex, delta, funcSize, calleeSaveRegisters[i]);
197     }
198     aotInfo.UpdateCurTextSecOffset(textSize);
199     if (rodataSizeAfterText != 0) {
200         aotInfo.AlignTextSec(AOTFileInfo::RODATA_SEC_ALIGN);
201         aotInfo.UpdateCurTextSecOffset(rodataSizeAfterText);
202     }
203 }
204 
205 #ifdef COMPILE_MAPLE
CollectFuncEntryInfoByLiteCG(std::map<uintptr_t,std::string> & addr2name,AnFileInfo & aotInfo,uint32_t fileIndex,uint32_t moduleIndex)206 void Module::CollectFuncEntryInfoByLiteCG(std::map<uintptr_t, std::string> &addr2name, AnFileInfo &aotInfo,
207                                           uint32_t fileIndex, uint32_t moduleIndex)
208 {
209     std::vector<std::tuple<uint64_t, size_t, int, bool>> funcInfo; // entry idx delta
210     std::vector<kungfu::CalleeRegAndOffsetVec> calleeSaveRegisters; // entry idx delta
211     // 1.Compile all functions and collect function infos
212     LMIRModule *lmirModule = static_cast<LMIRModule*>(irModule_);
213     LiteCGAssembler *assembler = static_cast<LiteCGAssembler*>(assembler_);
214     const auto &func2Addr = assembler->GetCodeInfo().GetFuncInfos();
215     lmirModule->IteratefuncIndexMap([&](size_t idx, std::string funcName, bool isFastCall) {
216         auto itr = func2Addr.find(funcName);
217         if (itr == func2Addr.end()) {
218             LOG_COMPILER(FATAL) << "get function address from emitter failed";
219             UNREACHABLE();
220         }
221         uint64_t funcEntry = itr->second.addr;
222         addr2name[funcEntry] = funcName;
223         int delta = itr->second.fp2PrevFrameSpDelta;
224         ASSERT(delta >= 0 && (delta % sizeof(uintptr_t) == 0));
225         funcInfo.emplace_back(std::tuple(funcEntry, idx, delta, isFastCall));
226         kungfu::CalleeRegAndOffsetVec info = itr->second.calleeRegInfo;
227         calleeSaveRegisters.emplace_back(info);
228     });
229     // 2.After all functions compiled, the module sections would be fixed
230     uint32_t textSize = GetTextSize();
231     uint32_t rodataSizeBeforeText = 0;
232     uint32_t rodataSizeAfterText = 0;
233 
234     aotInfo.AlignTextSec(AOTFileInfo::PAGE_ALIGN);
235     if (rodataSizeBeforeText != 0) {
236         aotInfo.UpdateCurTextSecOffset(rodataSizeBeforeText);
237         aotInfo.AlignTextSec(AOTFileInfo::TEXT_SEC_ALIGN);
238     }
239 
240     const size_t funcCount = funcInfo.size();
241     funcCount_ = funcCount;
242     startIndex_ = aotInfo.GetEntrySize();
243     // 3.Add function entries based on the module sections
244     for (size_t i = 0; i < funcInfo.size(); i++) {
245         uint64_t funcEntry = 0;
246         size_t idx;
247         int delta;
248         bool isFastCall;
249         uint32_t funcSize;
250         std::tie(funcEntry, idx, delta, isFastCall) = funcInfo[i];
251         if (i < funcCount - 1) {
252             funcSize = std::get<0>(funcInfo[i + 1]) - funcEntry;
253         } else {
254             funcSize = textSize - funcEntry;
255         }
256         auto found = addr2name[funcEntry].find(panda::ecmascript::JSPandaFile::ENTRY_FUNCTION_NAME);
257         bool isMainFunc = found != std::string::npos;
258         uint64_t offset = funcEntry;
259         aotInfo.AddEntry(CallSignature::TargetKind::JSFUNCTION, isMainFunc, isFastCall, idx,
260                          offset, fileIndex, moduleIndex, delta, funcSize, calleeSaveRegisters[i]);
261     }
262     aotInfo.UpdateCurTextSecOffset(textSize);
263     if (rodataSizeAfterText != 0) {
264         aotInfo.AlignTextSec(AOTFileInfo::RODATA_SEC_ALIGN);
265         aotInfo.UpdateCurTextSecOffset(rodataSizeAfterText);
266     }
267 }
268 #endif
269 
CollectModuleSectionDes(ModuleSectionDes & moduleDes) const270 void Module::CollectModuleSectionDes(ModuleSectionDes &moduleDes) const
271 {
272     if (irModule_->GetModuleKind() != MODULE_LLVM) {
273         std::cout << "CollectModuleSectionDes is not supported for litecg currently" << std::endl;
274         return;
275     }
276     ASSERT(assembler_ != nullptr);
277     LLVMAssembler *assembler = static_cast<LLVMAssembler *>(assembler_);
278     assembler->IterateSecInfos([&](size_t i, std::pair<uint8_t *, size_t> secInfo) {
279         auto curSec = ElfSection(i);
280         ElfSecName sec = curSec.GetElfEnumValue();
281         moduleDes.SetSecAddrAndSize(sec, reinterpret_cast<uint64_t>(secInfo.first), secInfo.second);
282         moduleDes.SetStartIndex(startIndex_);
283         moduleDes.SetFuncCount(funcCount_);
284     });
285     CollectStackMapDes(moduleDes);
286 }
287 
CollectAnModuleSectionDes(ModuleSectionDes & moduleDes,uint64_t textOffset,CGStackMapInfo & stackMapInfo) const288 void Module::CollectAnModuleSectionDes(ModuleSectionDes &moduleDes, uint64_t textOffset,
289                                        CGStackMapInfo &stackMapInfo) const
290 {
291     ASSERT(assembler_ != nullptr);
292     assembler_->IterateSecInfos([&](size_t i, std::pair<uint8_t *, size_t> secInfo) {
293         auto curSec = ElfSection(i);
294         ElfSecName sec = curSec.GetElfEnumValue();
295         // aot need relocated; stub don't need collect relocated section
296         moduleDes.SetSecAddrAndSize(sec, reinterpret_cast<uint64_t>(secInfo.first), secInfo.second);
297         moduleDes.SetStartIndex(startIndex_);
298         moduleDes.SetFuncCount(funcCount_);
299     });
300     CollectAnStackMapDes(moduleDes, textOffset, stackMapInfo);
301 }
302 
GetSectionSize(ElfSecName sec) const303 uint32_t Module::GetSectionSize(ElfSecName sec) const
304 {
305     return assembler_->GetSectionSize(sec);
306 }
307 
GetSectionAddr(ElfSecName sec) const308 uintptr_t Module::GetSectionAddr(ElfSecName sec) const
309 {
310     return assembler_->GetSectionAddr(sec);
311 }
312 
RunAssembler(const CompilerLog & log,bool fastCompileMode,bool isJit,const std::string & filename)313 void Module::RunAssembler(const CompilerLog &log, bool fastCompileMode, bool isJit, const std::string &filename)
314 {
315     if (!IsLLVM()) {
316         assembler_->SetAotCodeCommentFile(filename);
317     } else {
318         assembler_->SetAotCodeCommentFile("");
319     }
320     assembler_->Run(log, fastCompileMode, isJit);
321 }
322 
DisassemblerFunc(std::map<uintptr_t,std::string> & addr2name,uint64_t textOffset,const CompilerLog & log,const MethodLogList & logList,std::ostringstream & codeStream)323 void Module::DisassemblerFunc(std::map<uintptr_t, std::string> &addr2name, uint64_t textOffset,
324                               const CompilerLog &log, const MethodLogList &logList, std::ostringstream &codeStream)
325 {
326     if (irModule_->GetModuleKind() != MODULE_LLVM) {
327         std::cout << "DisassemblerFunc is not supported for litecg currently" << std::endl;
328         return;
329     }
330     auto *assembler = static_cast<LLVMAssembler*>(assembler_);
331     assembler->Disassemble(addr2name, textOffset, log, logList, codeStream);
332 }
333 
DestroyModule()334 void Module::DestroyModule()
335 {
336     if (irModule_ != nullptr) {
337         delete irModule_;
338         irModule_ = nullptr;
339     }
340     if (assembler_ != nullptr) {
341         delete assembler_;
342         assembler_ = nullptr;
343     }
344 }
345 
CollectAsmStubCodeInfo(std::map<uintptr_t,std::string> & addr2name,uint32_t bridgeModuleIdx)346 void StubFileGenerator::CollectAsmStubCodeInfo(std::map<uintptr_t, std::string> &addr2name, uint32_t bridgeModuleIdx)
347 {
348     uint32_t funSize = 0;
349     for (size_t i = 0; i < asmModule_.GetFunctionCount(); i++) {
350         auto cs = asmModule_.GetCSign(i);
351         auto entryOffset = asmModule_.GetFunction(cs->GetID());
352         if (i < asmModule_.GetFunctionCount() - 1) {
353             auto nextcs = asmModule_.GetCSign(i + 1);
354             funSize = asmModule_.GetFunction(nextcs->GetID()) - entryOffset;
355         } else {
356             funSize = asmModule_.GetBufferSize() - entryOffset;
357         }
358         stubInfo_.AddEntry(cs->GetTargetKind(), false, false, cs->GetID(), entryOffset,
359                            AOTFileManager::STUB_FILE_INDEX, bridgeModuleIdx, 0, funSize);
360         ASSERT(!cs->GetName().empty());
361         addr2name[entryOffset] = cs->GetName();
362     }
363 }
364 
CollectCodeInfo()365 void StubFileGenerator::CollectCodeInfo()
366 {
367     std::map<uintptr_t, std::string> stubAddr2Name;
368     std::vector<std::vector<uintptr_t>> entryPoints(modulePackage_.size());
369 
370     if (!concurrentCompile_) {
371         for (size_t i = 0; i < modulePackage_.size(); ++i) {
372             entryPoints[i] = modulePackage_[i].GetFuncEntryPoints();
373         }
374     } else if (!modulePackage_.empty()) {
375         // For first module, run it in current thread.
376         // For others, run them in child threads and wait for finish.
377         std::vector<std::thread> threads;
378         for (size_t i = 1; i < modulePackage_.size(); ++i) {
379             threads.emplace_back([&, i]() {
380                 entryPoints[i] = modulePackage_[i].GetFuncEntryPoints();
381             });
382         }
383         entryPoints[0] = modulePackage_[0].GetFuncEntryPoints();
384         for (auto& t : threads) {
385             if (t.joinable()) {
386                 t.join();
387             }
388         }
389     }
390 
391     for (size_t i = 0; i < modulePackage_.size(); ++i) {
392         modulePackage_[i].CollectFuncEntryInfo(entryPoints[i], stubAddr2Name, stubInfo_, i, GetLog());
393         ModuleSectionDes des;
394         modulePackage_[i].CollectModuleSectionDes(des);
395         stubInfo_.AddModuleDes(des);
396     }
397     std::map<uintptr_t, std::string> asmAddr2Name;
398     // idx for bridge module is the one after last module in modulePackage
399     CollectAsmStubCodeInfo(asmAddr2Name, modulePackage_.size());
400     if (log_->OutputASM()) {
401         DisassembleAsmStubs(asmAddr2Name);
402         DisassembleEachFunc(stubAddr2Name);
403     }
404 }
405 
DisassembleAsmStubs(std::map<uintptr_t,std::string> & addr2name)406 void StubFileGenerator::DisassembleAsmStubs(std::map<uintptr_t, std::string> &addr2name)
407 {
408     std::string tri = cfg_.GetTripleStr();
409     uint8_t *buf = reinterpret_cast<uint8_t*>(stubInfo_.GetAsmStubAddr());
410     size_t size = stubInfo_.GetAsmStubSize();
411     LLVMAssembler::Disassemble(&addr2name, tri, buf, size);
412 }
413 
RollbackTextSize(Module * module)414 uint64_t AOTFileGenerator::RollbackTextSize(Module *module)
415 {
416     uint64_t textAddr = module->GetSectionAddr(ElfSecName::TEXT);
417     uint32_t textSize = module->GetSectionSize(ElfSecName::TEXT);
418     uint64_t rodataAddrBeforeText = 0;
419     uint32_t rodataSizeBeforeText = 0;
420     uint64_t rodataAddrAfterText = 0;
421     uint32_t rodataSizeAfterText = 0;
422     if (module->IsLLVM()) {
423         // In llvm the ro section is separated from the text section, but these all in text section in LiteCG.
424         std::tie(rodataAddrBeforeText, rodataSizeBeforeText, rodataAddrAfterText, rodataSizeAfterText) =
425             module->GetMergedRODataAddrAndSize(textAddr);
426     }
427     uint64_t textStart = 0;
428     if (rodataSizeAfterText == 0) {
429         textStart = aotInfo_.GetCurTextSecOffset() - textSize;
430     } else {
431         textStart = aotInfo_.GetCurTextSecOffset() - textSize - rodataSizeAfterText;
432         textStart = AlignDown(textStart, AOTFileInfo::RODATA_SEC_ALIGN);
433     }
434     return textStart;
435 }
436 
CollectCodeInfo(Module * module,uint32_t moduleIdx)437 void AOTFileGenerator::CollectCodeInfo(Module *module, uint32_t moduleIdx)
438 {
439     std::map<uintptr_t, std::string> addr2name;
440     uint32_t lastEntryIdx = aotInfo_.GetEntrySize();
441     pgo::ApEntityId abcId = INVALID_INDEX;
442     pgo::PGOProfilerManager::GetInstance()->GetPandaFileId(curCompileFileName_.c_str(), abcId);
443     module->CollectFuncEntryInfo(addr2name, aotInfo_, abcId, moduleIdx, GetLog());
444     aotInfo_.MappingEntryFuncsToAbcFiles(curCompileFileName_, lastEntryIdx, aotInfo_.GetEntrySize());
445     ModuleSectionDes des;
446     uint64_t textOffset = RollbackTextSize(module);
447     if (stackMapInfo_ == nullptr) {
448         LOG_ECMA(FATAL) << "stackMapInfo_ isn't be initialized";
449         UNREACHABLE();
450     }
451     module->CollectAnModuleSectionDes(des, textOffset, *stackMapInfo_);
452 
453     aotInfo_.AddModuleDes(des);
454     if (module->IsLLVM() && log_->OutputASM()) {
455         module->DisassemblerFunc(addr2name, textOffset, *(log_), *(logList_), codeStream_);
456     }
457 }
458 
GetLatestModule()459 Module* AOTFileGenerator::GetLatestModule()
460 {
461     return &modulePackage_.back();
462 }
463 
GetModuleVecSize() const464 uint32_t AOTFileGenerator::GetModuleVecSize() const
465 {
466     return modulePackage_.size();
467 }
468 
AddModule(const std::string & name,const std::string & triple,LOptions option,bool logDebug,bool isJit)469 Module* AOTFileGenerator::AddModule(const std::string &name, const std::string &triple,
470                                     [[maybe_unused]] LOptions option, bool logDebug, [[maybe_unused]] bool isJit)
471 {
472 #ifdef COMPILE_MAPLE
473     if (useLiteCG_) {
474         LMIRModule *irModule = new LMIRModule(compilationEnv_->GetNativeAreaAllocator(), name, logDebug, triple, isJit);
475         LiteCGAssembler *ass = new LiteCGAssembler(*irModule, jitCodeSpace_,
476             compilationEnv_->GetJSOptions().GetCompilerCodegenOptions());
477         modulePackage_.emplace_back(Module(irModule, ass));
478         if (stackMapInfo_ == nullptr) {
479             stackMapInfo_ = new LiteCGStackMapInfo();
480         }
481         return &modulePackage_.back();
482     }
483 #endif
484     LLVMModule *m = new LLVMModule(compilationEnv_->GetNativeAreaAllocator(), name, logDebug, triple);
485     LLVMAssembler *ass = new LLVMAssembler(m, jitCodeSpace_, option);
486     modulePackage_.emplace_back(Module(m, ass));
487     if (stackMapInfo_ == nullptr) {
488         stackMapInfo_ = new LLVMStackMapInfo();
489     }
490     return &modulePackage_.back();
491 }
492 
AddModule(NativeAreaAllocator * allocator,const std::string & name,const std::string & triple,LOptions option,bool logDebug,StubFileKind kind)493 Module* StubFileGenerator::AddModule(NativeAreaAllocator *allocator, const std::string &name, const std::string &triple,
494                                      LOptions option, bool logDebug, StubFileKind kind)
495 {
496     LLVMModule* m = new LLVMModule(allocator, name, logDebug, triple);
497     switch (kind) {
498         case StubFileKind::BC:
499             m->SetUpForBytecodeHandlerStubs();
500             break;
501         case StubFileKind::COM:
502             m->SetUpForCommonStubs();
503             break;
504         case StubFileKind::BUILTIN:
505             m->SetUpForBuiltinsStubs();
506             break;
507         case StubFileKind::BASELINE:
508             m->SetUpForBaselineStubs();
509             break;
510         case StubFileKind::BC_STW_COPY:
511             m->SetUpForBytecodeStwCopyHandlerStubs();
512             break;
513         default:
514             LOG_ECMA(FATAL) << "unsupported stub file kind";
515             UNREACHABLE();
516             break;
517     }
518     LLVMAssembler* ass = new LLVMAssembler(m, jitCodeSpace_, option, true);
519     modulePackage_.emplace_back(Module(m, ass));
520     return &modulePackage_.back();
521 }
522 
RunLLVMAssembler()523 void StubFileGenerator::RunLLVMAssembler()
524 {
525     if (!concurrentCompile_) {
526         for (auto &m: modulePackage_) {
527             m.RunAssembler(*(this->log_), false);
528         }
529     } else if (!modulePackage_.empty()) {
530         // For first module, run it in current thread.
531         // For others, run them in child threads and wait for finish.
532         std::vector<std::thread> threads;
533         for (size_t i = 1; i < modulePackage_.size(); ++i) {
534             const CompilerLog &log = *(this->log_);
535             threads.emplace_back([&, i] {
536                 modulePackage_[i].RunAssembler(log, false);
537             });
538         }
539         modulePackage_[0].RunAssembler(*(this->log_), false);
540         for (auto& t : threads) {
541             if (t.joinable()) {
542                 t.join();
543             }
544         }
545     }
546 }
547 
RunAsmAssembler()548 void StubFileGenerator::RunAsmAssembler()
549 {
550     NativeAreaAllocator allocator;
551     Chunk chunk(&allocator);
552     asmModule_.Run(&cfg_, &chunk);
553 
554     auto buffer = asmModule_.GetBuffer();
555     auto bufferSize = asmModule_.GetBufferSize();
556     if (bufferSize == 0U) {
557         return;
558     }
559     stubInfo_.AddAsmStubELFInfo(asmModule_.GetCSigns(), asmModule_.GetStubsOffset());
560     stubInfo_.FillAsmStubTempHolder(buffer, bufferSize);
561     stubInfo_.accumulateTotalSize(bufferSize);
562 }
563 
SaveStubFile(const std::string & filename)564 void StubFileGenerator::SaveStubFile(const std::string &filename)
565 {
566     RunLLVMAssembler();
567     RunAsmAssembler();
568     CollectCodeInfo();
569     stubInfo_.Save(filename, cfg_.GetTriple());
570 }
571 
CompileLatestModuleThenDestroy(bool isJit)572 void AOTFileGenerator::CompileLatestModuleThenDestroy(bool isJit)
573 {
574     Module *latestModule = GetLatestModule();
575 #ifdef COMPILE_MAPLE
576     static uint32_t lastModulePC = 0;
577     if (useLiteCG_ && compilationEnv_->IsJitCompiler()) {
578         lastModulePC = 0;
579     }
580     if (latestModule->GetModule()->GetModuleKind() != MODULE_LLVM) {
581         LMIRModule *lmirModule = static_cast<LMIRModule*>(latestModule->GetModule());
582         lastModulePC = AlignUp(lastModulePC, AOTFileInfo::PAGE_ALIGN);
583         lmirModule->GetModule()->SetLastModulePC(lastModulePC);
584         // pass triple to litecg
585         lmirModule->GetModule()->SetIsAArch64(isAArch64());
586     }
587 #endif
588     ASSERT(GetModuleVecSize() > 0);
589     uint32_t latestModuleIdx = GetModuleVecSize() - 1;
590     {
591         TimeScope timescope("LLVMIROpt", const_cast<CompilerLog *>(log_));
592         bool fastCompileMode = compilationEnv_->GetJSOptions().GetFastAOTCompileMode();
593         latestModule->RunAssembler(*(log_), fastCompileMode, isJit, GetAotCodeCommentFile());
594     }
595     {
596         TimeScope timescope("LLVMCodeGen", const_cast<CompilerLog *>(log_));
597         CollectCodeInfo(latestModule, latestModuleIdx);
598     }
599     // message has been put into aotInfo, so latestModule could be destroyed
600 #ifdef COMPILE_MAPLE
601     if (latestModule->GetModule()->GetModuleKind() != MODULE_LLVM) {
602         LMIRModule *lmirModule = static_cast<LMIRModule*>(latestModule->GetModule());
603         lastModulePC = lmirModule->GetModule()->GetCurModulePC();
604     }
605 #endif
606     latestModule->DestroyModule();
607 }
608 
DestroyCollectedStackMapInfo()609 void AOTFileGenerator::DestroyCollectedStackMapInfo()
610 {
611     if (stackMapInfo_ != nullptr) {
612         delete stackMapInfo_;
613         stackMapInfo_ = nullptr;
614     }
615 }
616 
GenerateMergedStackmapSection()617 void AOTFileGenerator::GenerateMergedStackmapSection()
618 {
619     ArkStackMapBuilder builder;
620     std::shared_ptr<uint8_t> ptr = nullptr;
621     uint32_t size = 0;
622     if (stackMapInfo_ == nullptr) {
623         LOG_ECMA(FATAL) << "stackMapInfo_ isn't be initialized";
624         UNREACHABLE();
625     }
626     std::tie(ptr, size) = builder.GenerateArkStackMap(*stackMapInfo_, cfg_.GetTriple());
627     aotInfo_.UpdateStackMap(ptr, size, 0);
628     DestroyCollectedStackMapInfo();
629 }
630 
CreateDirIfNotExist(const std::string & filename)631 bool AOTFileGenerator::CreateDirIfNotExist(const std::string &filename)
632 {
633     std::string realPath;
634     if (!panda::ecmascript::RealPath(filename, realPath, false)) {
635         return false;
636     }
637     auto index = realPath.find_last_of('/');
638     if (index == std::string::npos) {
639         return true;
640     }
641     std::string path = realPath.substr(0, index);
642     if (!panda::ecmascript::ForceCreateDirectory(path)) {
643         LOG_COMPILER(ERROR) << "Fail to make dir: " << path;
644         return false;
645     }
646     return panda::ecmascript::SetDirModeAsDefault(path);
647 }
648 
SaveAOTFile(const std::string & filename,const std::string & appSignature,const std::unordered_map<CString,uint32_t> & fileNameToChecksumMap)649 bool AOTFileGenerator::SaveAOTFile(const std::string &filename, const std::string &appSignature,
650                                    const std::unordered_map<CString, uint32_t> &fileNameToChecksumMap)
651 {
652     if (aotInfo_.GetTotalCodeSize() == 0) {
653         LOG_COMPILER(WARN) << "error: code size of generated an file is empty!";
654         return false;
655     }
656     if (!CreateDirIfNotExist(filename)) {
657         LOG_COMPILER(ERROR) << "Fail to access dir: " << filename;
658         return false;
659     }
660     PrintMergedCodeComment();
661     GenerateMergedStackmapSection();
662     aotInfo_.GenerateMethodToEntryIndexMap();
663     if (!aotInfo_.Save(filename, cfg_.GetTriple(), anFileMaxByteSize_, fileNameToChecksumMap)) {
664         LOG_COMPILER(ERROR) << "Fail to save an file: " << filename;
665         return false;
666     }
667     if (!panda::ecmascript::SetFileModeAsDefault(filename)) {
668         LOG_COMPILER(ERROR) << "Fail to set an file mode:" << filename;
669         return false;
670     }
671     SetSecurityLabel(filename);
672     panda::ecmascript::CodeSignatureForAOTFile(filename, appSignature);
673     return true;
674 }
675 
SaveEmptyAOTFile(const std::string & filename,const std::string & appSignature,bool isAnFile)676 void AOTFileGenerator::SaveEmptyAOTFile(const std::string& filename, const std::string& appSignature, bool isAnFile)
677 {
678     if (!CreateDirIfNotExist(filename)) {
679         LOG_COMPILER(ERROR) << "Fail to access dir: " << filename;
680         return;
681     }
682     std::string realPath;
683     if (!RealPath(filename, realPath, false)) {
684         LOG_COMPILER(ERROR) << "Fail to get realPath: " << filename;
685         return;
686     }
687     if (FileExist(realPath.c_str())) {
688         LOG_COMPILER(ERROR) << "AOT file: " << realPath << " exist, skip create empty file";
689         return;
690     }
691     const char* rawPath = realPath.c_str();
692     std::ofstream file(rawPath, std::ofstream::binary);
693     file.close();
694     if (!panda::ecmascript::SetFileModeAsDefault(filename)) {
695         LOG_COMPILER(ERROR) << "Fail to set file mode: " << filename;
696     }
697     if (isAnFile) {
698         panda::ecmascript::CodeSignatureForAOTFile(filename, appSignature);
699     }
700     LOG_COMPILER(ERROR) << "create empty AOT file: " << realPath << " due to illegal AP file";
701 }
702 
GetMemoryCodeInfos(MachineCodeDesc & machineCodeDesc)703 bool AOTFileGenerator::GetMemoryCodeInfos(MachineCodeDesc &machineCodeDesc)
704 {
705     if (aotInfo_.GetTotalCodeSize() == 0) {
706         LOG_COMPILER(WARN) << "error: code size of generated an file is empty!";
707         return false;
708     }
709 
710     if (log_->OutputASM()) {
711         PrintMergedCodeComment();
712     }
713     GenerateMergedStackmapSection();
714 
715     // get func entry Map
716     aotInfo_.GenerateMethodToEntryIndexMap();
717 
718     uint64_t funcEntryAddr = reinterpret_cast<uint64_t>(aotInfo_.GetStubs().data());
719     ASSERT(aotInfo_.GetStubs().size() <= 2); // jsfunc + __llvm_deoptimize, 2 : size
720     uint32_t funcEntrySize = sizeof(AOTFileInfo::FuncEntryDes) * aotInfo_.GetStubs().size();
721 
722     ASSERT(aotInfo_.GetModuleSectionDes().size() == 1);
723     auto &moduleSectionDes = aotInfo_.GetModuleSectionDes()[0];
724     // get code data
725     uint64_t textAddr = moduleSectionDes.GetSecAddr(ElfSecName::TEXT);
726     size_t textSize = moduleSectionDes.GetSecSize(ElfSecName::TEXT);
727 
728     uint64_t rodataAddrBeforeText = 0;
729     uint32_t rodataSizeBeforeText = 0;
730     uint64_t rodataAddrAfterText = 0;
731     uint32_t rodataSizeAfterText = 0;
732     std::tie(rodataAddrBeforeText, rodataSizeBeforeText, rodataAddrAfterText, rodataSizeAfterText) =
733         moduleSectionDes.GetMergedRODataAddrAndSize(textAddr);
734 
735     machineCodeDesc.rodataAddrBeforeText = rodataAddrBeforeText;
736     machineCodeDesc.rodataSizeBeforeText = rodataSizeBeforeText;
737     machineCodeDesc.rodataAddrAfterText = rodataAddrAfterText;
738     machineCodeDesc.rodataSizeAfterText = rodataSizeAfterText;
739 
740 #ifdef JIT_ENABLE_CODE_SIGN
741     machineCodeDesc.codeSigner = 0;
742     JitSignCode *singleton = JitSignCode::GetInstance();
743     if (singleton->GetCodeSigner() != 0) {
744         LOG_JIT(DEBUG) << "In GetMemoryCodeInfos, signer = " << singleton->GetCodeSigner();
745         LOG_JIT(DEBUG) << "     signTableSize = " << singleton->signTableSize_;
746         machineCodeDesc.codeSigner = reinterpret_cast<uintptr_t>(singleton->GetCodeSigner());
747     }
748 #endif
749 
750     uint64_t stackMapPtr = reinterpret_cast<uint64_t>(moduleSectionDes.GetArkStackMapSharePtr().get());
751     size_t stackMapSize = moduleSectionDes.GetArkStackMapSize();
752 
753     auto *jitCompilationEnv = static_cast<JitCompilationEnv*>(compilationEnv_);
754     const auto &heapConstantTable = jitCompilationEnv->GetHeapConstantTable();
755     if (!heapConstantTable.empty()) {
756         machineCodeDesc.heapConstantTableAddr = reinterpret_cast<uintptr_t>(heapConstantTable.data());
757         machineCodeDesc.heapConstantTableSize = heapConstantTable.size() * sizeof(uintptr_t);
758     }
759 
760     machineCodeDesc.codeAddr = textAddr;
761     machineCodeDesc.codeSize = textSize;
762     machineCodeDesc.funcEntryDesAddr = funcEntryAddr;
763     machineCodeDesc.funcEntryDesSize = funcEntrySize;
764     machineCodeDesc.stackMapOrOffsetTableAddr = stackMapPtr;
765     machineCodeDesc.stackMapOrOffsetTableSize = stackMapSize;
766     machineCodeDesc.codeType = MachineCodeType::FAST_JIT_CODE;
767 
768     if (Jit::GetInstance()->IsEnableJitFort() && Jit::GetInstance()->IsEnableAsyncCopyToFort() &&
769         JitCompiler::AllocFromFortAndCopy(*compilationEnv_, machineCodeDesc) == false) {
770         return false;
771     }
772     return true;
773 }
774 
JitCreateLitecgModule()775 void AOTFileGenerator::JitCreateLitecgModule()
776 {
777 #ifdef COMPILE_MAPLE
778     Module *latestModule = GetLatestModule();
779     if (latestModule->GetModule()->GetModuleKind() != MODULE_LLVM) {
780         LMIRModule *lmirModule = static_cast<LMIRModule*>(latestModule->GetModule());
781         lmirModule->JitCreateLitecgModule();
782     }
783 #endif
784 }
785 
isAArch64() const786 bool AOTFileGenerator::isAArch64() const
787 {
788     return cfg_.IsAArch64();
789 }
790 
SaveSnapshotFile()791 bool AOTFileGenerator::SaveSnapshotFile()
792 {
793     TimeScope timescope("LLVMCodeGenPass-AI", const_cast<CompilerLog *>(log_));
794     Snapshot snapshot(compilationEnv_->GetEcmaVM());
795     const CString snapshotPath(compilationEnv_->GetJSOptions().GetAOTOutputFile().c_str());
796     const auto &methodToEntryIndexMap = aotInfo_.GetMethodToEntryIndexMap();
797     PGOTypeManager *ptManager = compilationEnv_->GetPTManager();
798     ptManager->GetAOTSnapshot().ResolveSnapshotData(methodToEntryIndexMap);
799 
800     CString aiPath = snapshotPath + AOTFileManager::FILE_EXTENSION_AI;
801     if (!CreateDirIfNotExist(aiPath.c_str())) {
802         LOG_COMPILER(ERROR) << "Fail to access dir: " << aiPath;
803         return false;
804     }
805     snapshot.Serialize(aiPath);
806     if (!panda::ecmascript::SetFileModeAsDefault(aiPath.c_str())) {
807         LOG_COMPILER(ERROR) << "Fail to set ai file mode:" << aiPath;
808         return false;
809     }
810     SetSecurityLabel(aiPath.c_str());
811     return true;
812 }
813 
ExtractPrefix(const std::string & filename)814 std::string AOTFileGenerator::ExtractPrefix(const std::string &filename)
815 {
816     std::string file = filename.substr(filename.find_last_of('/') + 1);
817     size_t dotPos = file.find_last_of('.');
818     if (dotPos == std::string::npos) {
819         LOG_COMPILER(ERROR) << "Path: " << file << " is illegal";
820         return "";
821     }
822 
823     std::string prefix = file.substr(0, dotPos);
824     return prefix;
825 }
826 
GenAotCodeCommentFileName(const std::string & filename)827 std::string AOTFileGenerator::GenAotCodeCommentFileName(const std::string &filename)
828 {
829     size_t lastSlashPos = filename.find_last_of('/');
830     std::string dirPath = filename.substr(0, lastSlashPos + 1);
831     std::string prefix = ExtractPrefix(filename);
832     std::string aotCodeCommentFilePath = "";
833     if (!prefix.empty()) {
834         aotCodeCommentFilePath = dirPath + "aot_code_comment_" + prefix + ".txt";
835         SetAotCodeCommentFile(aotCodeCommentFilePath);
836     } else {
837         SetAotCodeCommentFile("");
838     }
839     return aotCodeCommentFilePath;
840 }
841 
CreateAOTCodeCommentFile(const std::string & filename)842 bool AOTFileGenerator::CreateAOTCodeCommentFile(const std::string &filename)
843 {
844     if (!CreateDirIfNotExist(filename)) {
845         LOG_COMPILER(ERROR) << "Fail to access dir: " << filename;
846         return false;
847     }
848 
849     std::string realPath;
850     if (!panda::ecmascript::RealPath(filename, realPath, false)) {
851         LOG_COMPILER(ERROR) << "Fail to get realPath: " << filename;
852         return false;
853     }
854 
855     auto index = realPath.find_last_of('/');
856     if (index == std::string::npos) {
857         LOG_COMPILER(ERROR) << "Path: " << realPath << " is illegal";
858         return false;
859     }
860 
861     std::string aotCodeCommentFile = GenAotCodeCommentFileName(realPath);
862     if (aotCodeCommentFile.empty()) {
863         LOG_COMPILER(ERROR) << "Failed to generate aot code comment file";
864         return false;
865     }
866 
867     if (FileExist(aotCodeCommentFile.c_str())) {
868         if (Unlink(aotCodeCommentFile.c_str()) == -1) {
869             SetAotCodeCommentFile("");
870             LOG_COMPILER(ERROR) << "remove " << aotCodeCommentFile << " failed and errno is " << errno;
871             return false;
872         }
873     }
874 
875     std::string aotRealPath;
876     if (!panda::ecmascript::RealPath(aotCodeCommentFile, aotRealPath, false)) {
877         SetAotCodeCommentFile("");
878         LOG_COMPILER(ERROR) << "Fail to get realPath: " << aotCodeCommentFile;
879         return false;
880     }
881 
882     std::ofstream file(aotRealPath.c_str(), std::ofstream::app);
883     if (!file.is_open()) {
884         SetAotCodeCommentFile("");
885         LOG_COMPILER(ERROR) << "Failed to create " << aotCodeCommentFile;
886         return false;
887     }
888     file.close();
889 
890     if (!panda::ecmascript::SetFileModeAsDefault(aotCodeCommentFile)) {
891         SetAotCodeCommentFile("");
892         Unlink(aotCodeCommentFile.c_str());
893         LOG_COMPILER(ERROR) << "Fail to set file mode: " << aotCodeCommentFile;
894         return false;
895     }
896     return true;
897 }
898 }  // namespace panda::ecmascript::kungfu
899