• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef ECMASCRIPT_COMPILER_LLVM_LLVMSTACKPARSE_H
17 #define ECMASCRIPT_COMPILER_LLVM_LLVMSTACKPARSE_H
18 
19 #include <iostream>
20 #include <memory>
21 #include <tuple>
22 #include <unordered_map>
23 #include <vector>
24 #include "ecmascript/common.h"
25 #include "ecmascript/ecma_macros.h"
26 #include "ecmascript/interpreter/interpreter-inl.h"
27 
28 namespace panda::ecmascript::kungfu {
29 using OffsetType = int32_t;
30 using DwarfRegType = uint16_t;
31 using DwarfRegAndOffsetType = std::pair<DwarfRegType, OffsetType>;
32 using CallSiteInfo = std::vector<DwarfRegAndOffsetType>;
33 using Fun2InfoType = std::pair<uintptr_t, DwarfRegAndOffsetType>;
34 
35 struct Header {
36     uint8_t  stackmapversion; // Stack Map Version (current version is 3)
37     uint8_t  Reserved0; // Reserved (expected to be 0)
38     uint16_t Reserved1; // Reserved (expected to be 0)
PrintHeader39     void Print() const
40     {
41         LOG_ECMA(DEBUG) << "----- head ----";
42         LOG_ECMA(DEBUG) << "   version:" << static_cast<int>(stackmapversion);
43         LOG_ECMA(DEBUG) << "+++++ head ++++";
44     }
45 };
46 
47 #pragma pack(1)
48 struct StkSizeRecordTy {
49     uintptr_t functionAddress;
50     uint64_t stackSize;
51     uint64_t recordCount;
PrintStkSizeRecordTy52     void Print() const
53     {
54         LOG_ECMA(DEBUG) << "               functionAddress:0x" << std::hex << functionAddress;
55         LOG_ECMA(DEBUG) << "               stackSize:0x" << std::hex << stackSize;
56         LOG_ECMA(DEBUG) << "               recordCount:" << std::hex << recordCount;
57     }
58 };
59 #pragma pack()
60 
61 struct ConstantsTy {
62     uintptr_t LargeConstant;
PrintConstantsTy63     void Print() const
64     {
65         LOG_ECMA(DEBUG) << "               LargeConstant:0x" << std::hex << LargeConstant;
66     }
67 };
68 
69 struct StkMapRecordHeadTy {
70     uint64_t PatchPointID;
71     uint32_t InstructionOffset;
72     uint16_t Reserved;
73     uint16_t NumLocations;
PrintStkMapRecordHeadTy74     void Print() const
75     {
76         LOG_ECMA(DEBUG) << "               PatchPointID:0x" << std::hex << PatchPointID;
77         LOG_ECMA(DEBUG) << "               instructionOffset:0x" << std::hex << InstructionOffset;
78         LOG_ECMA(DEBUG) << "               Reserved:0x" << std::hex << Reserved;
79         LOG_ECMA(DEBUG) << "               NumLocations:0x" << std::hex << NumLocations;
80     }
81 };
82 
83 struct  LocationTy {
84     enum class Kind: uint8_t {
85         REGISTER = 1,
86         DIRECT = 2,
87         INDIRECT = 3,
88         CONSTANT = 4,
89         CONSTANTNDEX = 5,
90     };
91     Kind location;
92     uint8_t Reserved_0;
93     uint16_t LocationSize;
94     uint16_t DwarfRegNum;
95     uint16_t Reserved_1;
96     OffsetType OffsetOrSmallConstant;
97 
98     std::string PUBLIC_API TypeToString(Kind loc) const;
99 
PrintLocationTy100     void Print() const
101     {
102         LOG_ECMA(DEBUG)  << TypeToString(location);
103         LOG_ECMA(DEBUG) << ", size:" << std::dec << LocationSize;
104         LOG_ECMA(DEBUG) << "\tDwarfRegNum:" << DwarfRegNum;
105         LOG_ECMA(DEBUG) << "\t OffsetOrSmallConstant:" << OffsetOrSmallConstant;
106     }
107 };
108 
109 struct LiveOutsTy {
110     DwarfRegType DwarfRegNum;
111     uint8_t Reserved;
112     uint8_t SizeinBytes;
PrintLiveOutsTy113     void Print() const
114     {
115         LOG_ECMA(DEBUG) << "                  Dwarf RegNum:" << DwarfRegNum;
116         LOG_ECMA(DEBUG) << "                  Reserved:" << Reserved;
117         LOG_ECMA(DEBUG) << "                  SizeinBytes:" << SizeinBytes;
118     }
119 };
120 
121 struct StkMapRecordTy {
122     struct StkMapRecordHeadTy head;
123     std::vector<struct LocationTy> Locations;
124     std::vector<struct LiveOutsTy> LiveOuts;
PrintStkMapRecordTy125     void Print() const
126     {
127         head.Print();
128         auto size = Locations.size();
129         for (size_t i = 0; i < size; i++) {
130             LOG_ECMA(DEBUG) << "                   #" << std::dec << i << ":";
131             Locations[i].Print();
132         }
133         size = LiveOuts.size();
134         for (size_t i = 0; i < size; i++) {
135             LOG_ECMA(DEBUG) << "               liveOuts[" << i << "] info:";
136         }
137     }
138 };
139 
140 class DataInfo {
141 public:
DataInfo(std::unique_ptr<uint8_t[]> data)142     explicit DataInfo(std::unique_ptr<uint8_t[]> data): data_(std::move(data)), offset_(0) {}
~DataInfo()143     ~DataInfo()
144     {
145         data_.reset();
146         offset_ = 0;
147     }
148     template<class T>
Read()149     T Read()
150     {
151         T t = *reinterpret_cast<const T*>(data_.get() + offset_);
152         offset_ += sizeof(T);
153         return t;
154     }
GetOffset()155     unsigned int GetOffset() const
156     {
157         return offset_;
158     }
159 private:
160     std::unique_ptr<uint8_t[]> data_ {nullptr};
161     unsigned int offset_ {0};
162 };
163 
164 struct LLVMStackMap {
165     struct Header head;
166     std::vector<struct StkSizeRecordTy> StkSizeRecords;
167     std::vector<struct ConstantsTy> Constants;
168     std::vector<struct StkMapRecordTy> StkMapRecord;
PrintLLVMStackMap169     void Print() const
170     {
171         head.Print();
172         for (size_t i = 0; i < StkSizeRecords.size(); i++) {
173             LOG_ECMA(DEBUG) << "stkSizeRecord[" << i << "] info:";
174             StkSizeRecords[i].Print();
175         }
176         for (size_t i = 0; i < Constants.size(); i++) {
177             LOG_ECMA(DEBUG) << "constants[" << i << "] info:";
178             Constants[i].Print();
179         }
180         for (size_t i = 0; i < StkMapRecord.size(); i++) {
181             LOG_ECMA(DEBUG) << "StkMapRecord[" << i << "] info:";
182             StkMapRecord[i].Print();
183         }
184     }
185 };
186 
187 class LLVMStackMapParser {
188 public:
GetInstance()189     static LLVMStackMapParser& GetInstance()
190     {
191         static LLVMStackMapParser instance;
192         return instance;
193     }
194     bool PUBLIC_API CalculateStackMap(std::unique_ptr<uint8_t []> stackMapAddr);
195     bool PUBLIC_API CalculateStackMap(std::unique_ptr<uint8_t []> stackMapAddr,
196     uintptr_t hostCodeSectionAddr, uintptr_t deviceCodeSectionAddr);
Print()197     void PUBLIC_API Print() const
198     {
199         llvmStackMap_.Print();
200     }
201     const CallSiteInfo *GetCallSiteInfoByPc(uintptr_t funcAddr) const;
202     bool CollectStackMapSlots(uintptr_t callSiteAddr, uintptr_t frameFp, std::set<uintptr_t> &baseSet,
203                             ChunkMap<DerivedDataKey, uintptr_t> *data, [[maybe_unused]] bool isVerifying) const;
204     bool CollectStackMapSlots(OptimizedLeaveFrame *frame, std::set<uintptr_t> &baseSet,
205                             ChunkMap<DerivedDataKey, uintptr_t> *data,
206                             [[maybe_unused]] bool isVerifying) const;
207 
208 private:
LLVMStackMapParser()209     LLVMStackMapParser()
210     {
211         stackMapAddr_ = nullptr;
212         pc2CallSiteInfo_.clear();
213         pid2CallSiteInfo_.clear();
214         dataInfo_ = nullptr;
215     }
~LLVMStackMapParser()216     ~LLVMStackMapParser()
217     {
218         if (stackMapAddr_) {
219             stackMapAddr_.release();
220         }
221         pc2CallSiteInfo_.clear();
222         pid2CallSiteInfo_.clear();
223         dataInfo_ = nullptr;
224     }
225     void CalcCallSite();
226     bool IsDeriveredPointer(int callsitetime) const;
227     const CallSiteInfo* GetCallSiteInfoByPatchID(uint64_t patchPointId) const;
228     void PrintCallSiteInfo(const CallSiteInfo *infos, OptimizedLeaveFrame *frame) const;
229     void PrintCallSiteInfo(const CallSiteInfo *infos, uintptr_t *fp) const;
230     std::unique_ptr<uint8_t[]> stackMapAddr_;
231     struct LLVMStackMap llvmStackMap_;
232     std::unordered_map<uintptr_t, CallSiteInfo> pc2CallSiteInfo_;
233     std::unordered_map<uint64_t, CallSiteInfo> pid2CallSiteInfo_;
234     [[maybe_unused]] std::unique_ptr<DataInfo> dataInfo_;
235 };
236 } // namespace panda::ecmascript::kungfu
237 #endif  // ECMASCRIPT_COMPILER_LLVM_LLVMSTACKPARSE_H