• 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         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