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