• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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