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