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