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