1 /* 2 * Copyright (c) 2021-2022 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 #ifndef ECMASCRIPT_AOT_FILE_MANAGER_H 16 #define ECMASCRIPT_AOT_FILE_MANAGER_H 17 18 #include "ecmascript/compiler/binary_section.h" 19 #include "ecmascript/deoptimizer/calleeReg.h" 20 #include "ecmascript/js_function.h" 21 #include "ecmascript/js_runtime_options.h" 22 #include "ecmascript/stackmap/ark_stackmap.h" 23 24 namespace panda::ecmascript { 25 class JSpandafile; 26 class JSThread; 27 28 class BinaryBufferParser { 29 public: BinaryBufferParser(uint8_t * buffer,uint32_t length)30 BinaryBufferParser(uint8_t *buffer, uint32_t length) : buffer_(buffer), length_(length) {} 31 ~BinaryBufferParser() = default; 32 void ParseBuffer(void *dst, uint32_t count); 33 void ParseBuffer(uint8_t *dst, uint32_t count, uint8_t *src); 34 35 private: 36 uint8_t *buffer_ {nullptr}; 37 uint32_t length_ {0}; 38 uint32_t offset_ {0}; 39 }; 40 41 class ExecutedMemoryAllocator { 42 public: 43 struct ExeMem { 44 void *addr_ {nullptr}; 45 size_t size_ {0}; 46 }; 47 AllocateBuf(uint32_t size,ExeMem & exeMem)48 static void AllocateBuf(uint32_t size, ExeMem &exeMem) { 49 MemMap buf = MachineCodePageMap(AlignUp(size, PageSize()), PAGE_PROT_EXEC_READWRITE); 50 exeMem.addr_ = buf.GetMem(); 51 exeMem.size_ = buf.GetSize(); 52 } 53 DestoryBuf(ExeMem & exeMem)54 static void DestoryBuf(ExeMem &exeMem) { 55 if (exeMem.addr_ != nullptr) { 56 MachineCodePageUnmap(MemMap(exeMem.addr_, exeMem.size_)); 57 exeMem.addr_ = nullptr; 58 exeMem.size_ = 0; 59 } 60 } 61 }; 62 63 struct ModuleSectionDes { 64 std::map<ElfSecName, std::pair<uint64_t, uint32_t>> sectionsInfo_ {}; 65 uint32_t startIndex_ {static_cast<uint32_t>(-1)}; // record current module first function index in AOTFileInfo 66 uint32_t funcCount_ {0}; 67 std::shared_ptr<uint8_t> arkStackMapPtr_ {nullptr}; 68 uint32_t arkStackMapSize_ {0}; 69 uint8_t *arkStackMapRawPtr_ {nullptr}; 70 GetSecNameModuleSectionDes71 std::string GetSecName(const ElfSecName idx) const 72 { 73 switch (idx) { 74 case ElfSecName::RODATA: 75 return "rodata"; 76 case ElfSecName::RODATA_CST4: 77 return "rodata.cst4"; 78 case ElfSecName::RODATA_CST8: 79 return "rodata.cst8"; 80 case ElfSecName::RODATA_CST16: 81 return "rodata.cst16"; 82 case ElfSecName::RODATA_CST32: 83 return "rodata.cst32"; 84 case ElfSecName::TEXT: 85 return "text"; 86 case ElfSecName::DATA: 87 return "data"; 88 case ElfSecName::GOT: 89 return "got"; 90 case ElfSecName::RELATEXT: 91 return "rela.text"; 92 case ElfSecName::STRTAB: 93 return "strtab"; 94 case ElfSecName::SYMTAB: 95 return "symtab"; 96 case ElfSecName::LLVM_STACKMAP: 97 return "llvm_stackmaps"; 98 default: { 99 LOG_ECMA(FATAL) << "this branch is unreachable"; 100 UNREACHABLE(); 101 } 102 } 103 } 104 SetArkStackMapPtrModuleSectionDes105 void SetArkStackMapPtr(std::shared_ptr<uint8_t> ptr) 106 { 107 arkStackMapPtr_ = ptr; 108 } 109 GetArkStackMapSharePtrModuleSectionDes110 std::shared_ptr<uint8_t> GetArkStackMapSharePtr() 111 { 112 return std::move(arkStackMapPtr_); 113 } 114 SetArkStackMapPtrModuleSectionDes115 void SetArkStackMapPtr(uint8_t *ptr) 116 { 117 arkStackMapRawPtr_ = ptr; 118 } 119 GetArkStackMapRawPtrModuleSectionDes120 uint8_t* GetArkStackMapRawPtr() 121 { 122 return arkStackMapRawPtr_; 123 } 124 SetArkStackMapSizeModuleSectionDes125 void SetArkStackMapSize(uint32_t size) 126 { 127 arkStackMapSize_ = size; 128 } 129 GetArkStackMapSizeModuleSectionDes130 uint32_t GetArkStackMapSize() const 131 { 132 return arkStackMapSize_; 133 } 134 SetStartIndexModuleSectionDes135 void SetStartIndex(uint32_t index) 136 { 137 startIndex_ = index; 138 } 139 GetStartIndexModuleSectionDes140 uint32_t GetStartIndex() const 141 { 142 return startIndex_; 143 } 144 SetFuncCountModuleSectionDes145 void SetFuncCount(uint32_t cnt) 146 { 147 funcCount_ = cnt; 148 } 149 GetFuncCountModuleSectionDes150 uint32_t GetFuncCount() const 151 { 152 return funcCount_; 153 } 154 155 ModuleSectionDes() = default; 156 SetSecAddrModuleSectionDes157 void SetSecAddr(uint64_t addr, ElfSecName idx) 158 { 159 sectionsInfo_[idx].first = addr; 160 } 161 GetSecAddrModuleSectionDes162 uint64_t GetSecAddr(const ElfSecName idx) const 163 { 164 auto it = sectionsInfo_.find(idx); 165 return it == sectionsInfo_.end() ? 0 : it->second.first; 166 } 167 EraseSecModuleSectionDes168 void EraseSec(ElfSecName idx) 169 { 170 sectionsInfo_.erase(idx); 171 } 172 SetSecSizeModuleSectionDes173 void SetSecSize(uint32_t size, ElfSecName idx) 174 { 175 sectionsInfo_[idx].second = size; 176 } 177 GetSecSizeModuleSectionDes178 uint32_t GetSecSize(const ElfSecName idx) const 179 { 180 auto it = sectionsInfo_.find(idx); 181 return it == sectionsInfo_.end() ? 0 : it->second.second; 182 } 183 GetSecInfosSizeModuleSectionDes184 uint32_t GetSecInfosSize() 185 { 186 return sectionsInfo_.size(); 187 } 188 ContainCodeModuleSectionDes189 bool ContainCode(uintptr_t pc) const 190 { 191 uint64_t stubStartAddr = GetSecAddr(ElfSecName::TEXT); 192 uint64_t stubEndAddr = stubStartAddr + GetSecSize(ElfSecName::TEXT); 193 return (pc >= stubStartAddr && pc <= stubEndAddr); 194 } 195 196 void SaveSectionsInfo(std::ofstream &file); 197 void LoadSectionsInfo(BinaryBufferParser &parser, uint32_t &curUnitOffset, 198 uint64_t codeAddress); 199 void LoadStackMapSection(BinaryBufferParser &parser, uintptr_t secBegin, uint32_t &curUnitOffset); 200 void LoadSectionsInfo(std::ifstream &file, uint32_t &curUnitOffset, 201 uint64_t codeAddress); 202 void LoadStackMapSection(std::ifstream &file, uintptr_t secBegin, uint32_t &curUnitOffset); 203 204 private: 205 static constexpr int DECIMAL_LENS = 2; 206 static constexpr int HUNDRED_TIME = 100; 207 static constexpr int PERCENT_LENS = 4; 208 }; 209 210 class PUBLIC_API AOTFileInfo { 211 public: 212 using CallSignature = kungfu::CallSignature; 213 AOTFileInfo() = default; 214 virtual ~AOTFileInfo() = default; 215 216 struct FuncEntryDes { 217 uint64_t codeAddr_; 218 CallSignature::TargetKind kind_; 219 bool isMainFunc_; 220 uint32_t indexInKindOrMethodId_; 221 uint32_t moduleIndex_; 222 int fpDeltaPrevFrameSp_; 223 uint32_t funcSize_; 224 [[maybe_unused]] uint32_t calleeRegisterNum_; 225 int32_t CalleeReg2Offset_[2 * kungfu::MAX_CALLEE_SAVE_REIGISTER_NUM]; IsStubFuncEntryDes226 bool IsStub() const 227 { 228 return CallSignature::TargetKind::STUB_BEGIN <= kind_ && kind_ < CallSignature::TargetKind::STUB_END; 229 } 230 IsBCStubFuncEntryDes231 bool IsBCStub() const 232 { 233 return CallSignature::TargetKind::BCHANDLER_BEGIN <= kind_ && 234 kind_ < CallSignature::TargetKind::BCHANDLER_END; 235 } 236 IsBCHandlerStubFuncEntryDes237 bool IsBCHandlerStub() const 238 { 239 return (kind_ == CallSignature::TargetKind::BYTECODE_HANDLER); 240 } 241 IsBuiltinsStubFuncEntryDes242 bool IsBuiltinsStub() const 243 { 244 return (kind_ == CallSignature::TargetKind::BUILTINS_STUB || 245 kind_ == CallSignature::TargetKind::BUILTINS_WITH_ARGV_STUB); 246 } 247 IsCommonStubFuncEntryDes248 bool IsCommonStub() const 249 { 250 return (kind_ == CallSignature::TargetKind::COMMON_STUB); 251 } 252 IsGeneralRTStubFuncEntryDes253 bool IsGeneralRTStub() const 254 { 255 return (kind_ >= CallSignature::TargetKind::RUNTIME_STUB && 256 kind_ <= CallSignature::TargetKind::DEOPT_STUB); 257 } 258 }; 259 GetStubDes(int index)260 const FuncEntryDes& GetStubDes(int index) const 261 { 262 return entries_[index]; 263 } 264 GetEntrySize()265 uint32_t GetEntrySize() const 266 { 267 return entries_.size(); 268 } 269 GetStubs()270 const std::vector<FuncEntryDes>& GetStubs() const 271 { 272 return entries_; 273 } 274 GetCodeUnits()275 const std::vector<ModuleSectionDes>& GetCodeUnits() const 276 { 277 return des_; 278 } 279 GetStubNum()280 uint32_t GetStubNum() const 281 { 282 return entryNum_; 283 } 284 SetStubNum(uint32_t n)285 void SetStubNum(uint32_t n) 286 { 287 entryNum_ = n; 288 } 289 290 void AddEntry(CallSignature::TargetKind kind, bool isMainFunc, int indexInKind, uint64_t offset, 291 uint32_t moduleIndex, int delta, uint32_t size, kungfu::CalleeRegAndOffsetVec info = {}) 292 { 293 FuncEntryDes des; 294 if (memset_s(&des, sizeof(des), 0, sizeof(des)) != EOK) { 295 LOG_FULL(FATAL) << "memset_s failed"; 296 return; 297 } 298 des.kind_ = kind; 299 des.isMainFunc_ = isMainFunc; 300 des.indexInKindOrMethodId_ = static_cast<uint32_t>(indexInKind); 301 des.codeAddr_ = offset; 302 des.moduleIndex_ = moduleIndex; 303 des.fpDeltaPrevFrameSp_ = delta; 304 des.funcSize_ = size; 305 des.calleeRegisterNum_ = info.size(); 306 kungfu::DwarfRegType reg = 0; 307 kungfu::OffsetType regOffset = 0; 308 for (size_t i = 0; i < info.size(); i ++) { 309 std::tie(reg, regOffset) = info[i]; 310 des.CalleeReg2Offset_[2 * i] = static_cast<int32_t>(reg); 311 des.CalleeReg2Offset_[2 * i + 1] = static_cast<int32_t>(regOffset); 312 } 313 entries_.emplace_back(des); 314 } 315 GetModuleSectionDes()316 const std::vector<ModuleSectionDes> &GetModuleSectionDes() const 317 { 318 return des_; 319 } 320 GetCodeUnitsNum()321 size_t GetCodeUnitsNum() 322 { 323 return des_.size(); 324 } 325 accumulateTotalSize(uint32_t size)326 void accumulateTotalSize(uint32_t size) 327 { 328 totalCodeSize_ += size; 329 } 330 331 using CallSiteInfo = std::tuple<uint64_t, uint8_t *, int, kungfu::CalleeRegAndOffsetVec>; 332 333 bool CalCallSiteInfo(uintptr_t retAddr, CallSiteInfo& ret) const; 334 335 virtual void Destroy(); 336 337 protected: GetExeMem()338 ExecutedMemoryAllocator::ExeMem& GetExeMem() { 339 return exeMem_; 340 } 341 342 uint32_t entryNum_ {0}; 343 uint32_t moduleNum_ {0}; 344 uint32_t totalCodeSize_ {0}; 345 std::vector<FuncEntryDes> entries_ {}; 346 std::vector<ModuleSectionDes> des_ {}; 347 ExecutedMemoryAllocator::ExeMem exeMem_ {}; 348 }; 349 350 class PUBLIC_API AnFileInfo : public AOTFileInfo { 351 public: 352 AnFileInfo() = default; 353 ~AnFileInfo() override = default; 354 void Save(const std::string &filename, kungfu::Triple triple); AddModuleDes(ModuleSectionDes & moduleDes)355 void AddModuleDes(ModuleSectionDes &moduleDes) 356 { 357 des_.emplace_back(moduleDes); 358 for (auto &s : moduleDes.sectionsInfo_) { 359 auto sec = ElfSection(s.first); 360 if (sec.isSequentialAOTSec()) { 361 accumulateTotalSize(s.second.second); 362 } 363 } 364 accumulateTotalSize(moduleDes.GetArkStackMapSize()); 365 } 366 GetMainFuncEntry(uint32_t methodId)367 uintptr_t GetMainFuncEntry(uint32_t methodId) const 368 { 369 auto it = mainEntryMap_.find(methodId); 370 if (it == mainEntryMap_.end()) { 371 return 0; 372 } 373 return static_cast<uintptr_t>(it->second); 374 } 375 376 bool IsLoadMain(const JSPandaFile *jsPandaFile, const CString &entry) const; 377 IsLoad()378 bool IsLoad() const 379 { 380 return isLoad_; 381 } 382 383 void Destroy() override; 384 385 bool RewriteRelcateDeoptHandler(EcmaVM *vm); 386 GetHeader()387 Elf64_Ehdr GetHeader() 388 { 389 return header_; 390 } 391 392 private: 393 bool Load(const std::string &filename); 394 bool RewriteRelcateTextSection(const char* symbol, uintptr_t patchAddr); 395 std::unordered_map<uint32_t, uint64_t> mainEntryMap_ {}; 396 bool isLoad_ {false}; 397 Elf64_Ehdr header_; 398 399 friend class AnFileDataManager; 400 }; 401 402 class PUBLIC_API StubFileInfo : public AOTFileInfo { 403 public: 404 StubFileInfo() = default; 405 ~StubFileInfo() override = default; 406 void Save(const std::string &filename); 407 AddModuleDes(ModuleSectionDes & moduleDes)408 void AddModuleDes(ModuleSectionDes &moduleDes) 409 { 410 des_.emplace_back(moduleDes); 411 for (auto &s : moduleDes.sectionsInfo_) { 412 auto sec = ElfSection(s.first); 413 if (sec.isSequentialAOTSec()) { 414 accumulateTotalSize(s.second.second); 415 } 416 } 417 accumulateTotalSize(moduleDes.GetArkStackMapSize()); 418 } 419 GetAsmStubAddr()420 uint64_t GetAsmStubAddr() const 421 { 422 return reinterpret_cast<uint64_t>(asmStubAddr_); 423 } 424 GetAsmStubSize()425 uint32_t GetAsmStubSize() const 426 { 427 return static_cast<uint32_t>(asmStubSize_); 428 } 429 SetAsmStubAddr(void * addr)430 void SetAsmStubAddr(void *addr) 431 { 432 asmStubAddr_ = addr; 433 } 434 SetAsmStubAddr(uintptr_t addr)435 void SetAsmStubAddr(uintptr_t addr) 436 { 437 asmStubAddr_ = reinterpret_cast<void *>(addr); 438 } 439 SetAsmStubSize(size_t size)440 void SetAsmStubSize(size_t size) 441 { 442 asmStubSize_ = size; 443 } 444 FillAsmStubTempHolder(uint8_t * buffer,size_t bufferSize)445 void FillAsmStubTempHolder(uint8_t *buffer, size_t bufferSize) 446 { 447 asmStubTempHolder_.resize(bufferSize); 448 if (memcpy_s(asmStubTempHolder_.data(), bufferSize, buffer, bufferSize) != EOK) { 449 LOG_FULL(FATAL) << "memcpy_s failed"; 450 return; 451 } 452 SetAsmStubAddr(asmStubTempHolder_.data()); 453 SetAsmStubSize(bufferSize); 454 } 455 456 private: 457 bool Load(); 458 void *asmStubAddr_ {nullptr}; 459 size_t asmStubSize_ {0}; 460 std::vector<int> asmStubTempHolder_ {}; 461 462 friend class AnFileDataManager; 463 }; 464 465 class AOTLiteralInfo : public TaggedArray { 466 public: Cast(TaggedObject * object)467 static AOTLiteralInfo *Cast(TaggedObject *object) 468 { 469 ASSERT(JSTaggedValue(object).IsTaggedArray()); 470 return static_cast<AOTLiteralInfo *>(object); 471 } 472 }; 473 474 class AnFileDataManager { 475 public: 476 enum class Type : uint8_t { 477 STUB = 0, 478 AOT, 479 }; 480 481 static AnFileDataManager *GetInstance(); 482 ~AnFileDataManager(); 483 484 bool SafeLoad(const std::string &fileName, Type type, EcmaVM *vm = nullptr); 485 uint32_t SafeGetFileInfoIndex(const std::string &fileName); 486 std::shared_ptr<AnFileInfo> SafeGetAnFileInfo(uint32_t index); 487 std::shared_ptr<StubFileInfo> SafeGetStubFileInfo(); 488 bool SafeTryReadLock(); 489 bool SafeInsideStub(uintptr_t pc); 490 bool SafeInsideAOT(uintptr_t pc); 491 AOTFileInfo::CallSiteInfo SafeCalCallSiteInfo(uintptr_t retAddr); 492 void SafeDestoryAllData(); 493 void SafeDestroyAnData(const std::string &fileName); 494 GetDir()495 const std::string& GetDir() const 496 { 497 return anDir_; 498 } 499 IsEnable()500 bool IsEnable() const 501 { 502 return anEnable_; 503 } 504 505 // only main thread call this, only call once, no need to lock SetDir(std::string dir)506 void SetDir(std::string dir) 507 { 508 anDir_ = std::move(dir); 509 } 510 SetEnable(bool enable)511 void SetEnable(bool enable) 512 { 513 anEnable_ = enable; 514 } 515 516 private: 517 AnFileDataManager() = default; 518 std::shared_ptr<AnFileInfo> UnsafeFind(const std::string &fileName) const; 519 bool UnsafeLoadFromAOT(const std::string &fileName, EcmaVM *vm); 520 bool UnsafeLoadFromStub(); 521 uint32_t UnSafeGetFileInfoIndex(const std::string &fileName); UnSafeGetAnFileInfo(uint32_t index)522 std::shared_ptr<AnFileInfo> UnSafeGetAnFileInfo(uint32_t index) 523 { 524 return loadedAn_.at(index); 525 } 526 527 os::memory::RWLock lock_; 528 std::unordered_map<std::string, uint32_t> anFileNameToIndexMap_; 529 std::vector<std::shared_ptr<AnFileInfo>> loadedAn_ {}; 530 std::shared_ptr<StubFileInfo> loadedStub_ {nullptr}; 531 std::string anDir_; 532 bool anEnable_ {false}; 533 }; 534 535 class AOTFileManager { 536 public: 537 explicit AOTFileManager(EcmaVM *vm); 538 virtual ~AOTFileManager(); 539 540 static constexpr char FILE_EXTENSION_AN[] = ".an"; 541 static constexpr char FILE_EXTENSION_AI[] = ".ai"; 542 static constexpr uint8_t DESERI_CP_ITEM_SIZE = 2; 543 544 void LoadStubFile(const std::string &fileName); 545 bool LoadAnFile(const std::string &fileName); 546 AOTFileInfo::CallSiteInfo CalCallSiteInfo(uintptr_t retAddr) const; 547 bool TryReadLock() const; 548 bool InsideStub(uintptr_t pc) const; 549 bool InsideAOT(uintptr_t pc) const; 550 void Iterate(const RootVisitor &v); 551 552 const std::shared_ptr<AnFileInfo> GetAnFileInfo(const JSPandaFile *jsPandaFile) const; 553 bool IsLoad(const JSPandaFile *jsPandaFile) const; 554 bool IsLoadMain(const JSPandaFile *jsPandaFile, const CString &entry) const; 555 uint32_t GetAnFileIndex(const JSPandaFile *jsPandaFile) const; 556 void SetAOTMainFuncEntry(JSHandle<JSFunction> mainFunc, const JSPandaFile *jsPandaFile, 557 std::string_view entryPoint); 558 void SetAOTFuncEntry(const JSPandaFile *jsPandaFile, Method *method, uint32_t entryIndex); 559 void SetAOTFuncEntryForLiteral(const JSPandaFile *jsPandaFile, const TaggedArray *literal, 560 const AOTLiteralInfo *entryIndexes); 561 void LoadAiFile([[maybe_unused]] const std::string &filename); 562 void LoadAiFile(const JSPandaFile *jsPandaFile); 563 kungfu::ArkStackMapParser* GetStackMapParser() const; 564 static JSTaggedValue GetAbsolutePath(JSThread *thread, JSTaggedValue relativePathVal); 565 static bool GetAbsolutePath(const CString &relativePathCstr, CString &absPathCstr); 566 bool RewriteDataSection(uintptr_t dataSec, size_t size, uintptr_t newData, size_t newSize); 567 void AddConstantPool(const CString &snapshotFileName, JSTaggedValue deserializedCPList); 568 JSHandle<JSTaggedValue> GetDeserializedConstantPool(const JSPandaFile *jsPandaFile, int32_t cpID); 569 std::string GetAotFileName(EcmaVM *vm, const JSPandaFile *jsPandaFile, const std::string &extensionName) const; 570 571 private: 572 RewriteRelcateDeoptHandler(EcmaVM * vm,AnFileInfo AOTFileInfo)573 void RewriteRelcateDeoptHandler(EcmaVM *vm, AnFileInfo AOTFileInfo) 574 { 575 AOTFileInfo.RewriteRelcateDeoptHandler(vm); 576 } 577 578 void PrintAOTEntry(const JSPandaFile *file, const Method *method, uintptr_t entry); 579 void InitializeStubEntries(const std::vector<AnFileInfo::FuncEntryDes>& stubs); 580 void AdjustBCStubAndDebuggerStubEntries(JSThread *thread, const std::vector<AOTFileInfo::FuncEntryDes> &stubs, 581 const AsmInterParsedOption &asmInterOpt); 582 583 EcmaVM *vm_ {nullptr}; 584 ObjectFactory *factory_ {nullptr}; 585 std::unordered_map<uint32_t, CMap<int32_t, JSTaggedValue>> desCPs_ {}; 586 kungfu::ArkStackMapParser *arkStackMapParser_ {nullptr}; 587 588 friend class AnFileInfo; 589 friend class StubFileInfo; 590 }; 591 } // namespace panda::ecmascript 592 #endif // ECMASCRIPT_AOT_FILE_MANAGER_H 593