• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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_LLVM_STACKMAP_TYPE_H
16 #define ECMASCRIPT_LLVM_STACKMAP_TYPE_H
17 
18 #include <iostream>
19 #include <memory>
20 #include <tuple>
21 #include <unordered_map>
22 #include <variant>
23 #include <vector>
24 #include <cmath>
25 #include "ecmascript/base/bit_helper.h"
26 #include "ecmascript/common.h"
27 #include "ecmascript/compiler/assembler/assembler.h"
28 #include "ecmascript/log_wrapper.h"
29 #include "ecmascript/mem/mem.h"
30 #include "ecmascript/stackmap/cg_stackmap.h"
31 
32 #include "libpandabase/utils/leb128.h"
33 
34 namespace panda::ecmascript::kungfu {
35 struct LocationTy {
36     enum class Kind: uint8_t {
37         REGISTER = 1,
38         DIRECT = 2,
39         INDIRECT = 3,
40         CONSTANT = 4,
41         CONSTANTNDEX = 5,
42     };
43     static constexpr int CONSTANT_FIRST_ELEMENT_INDEX = 3;
44     // LLVM's stackmap = [cc, flags, numDeopt, <c0, l0>, .., gc-pair<base0, deriv0>, .. ] described in StackMaps.cpp
45     static constexpr int CONSTANT_DEOPT_CNT_INDEX = 2;
46 
47     Kind location;
48     uint8_t reserved_0;
49     uint16_t locationSize;
50     uint16_t dwarfRegNum;
51     uint16_t reserved_1;
52     int32_t offsetOrSmallConstant;
53 
54     std::string PUBLIC_API TypeToString(Kind loc) const;
55 
PrintLocationTy56     void Print() const
57     {
58         LOG_COMPILER(DEBUG)  << TypeToString(location);
59         LOG_COMPILER(DEBUG) << ", size:" << std::dec << locationSize;
60         LOG_COMPILER(DEBUG) << "\tDwarfRegNum:" << dwarfRegNum;
61         LOG_COMPILER(DEBUG) << "\t OffsetOrSmallConstant:" << offsetOrSmallConstant;
62     }
63 };
64 
65 class LLVMStackMapType {
66 public:
67     using OffsetType = int32_t;
68     using DwarfRegType = uint16_t;
69     using IntType = int32_t;
70     using LargeInt = int64_t;
71     using RegType = int8_t;
72     using KindType = int8_t;
73     using VRegId = int16_t;
74     using SLeb128Type = int64_t;
75     using DwarfRegAndOffsetType = std::pair<DwarfRegType, OffsetType>;
76     using CallSiteInfo = std::vector<DwarfRegAndOffsetType>;
77     using Fun2InfoType = std::pair<uintptr_t, DwarfRegAndOffsetType>;
78     using Pc2CallSiteInfo = std::unordered_map<uintptr_t, CallSiteInfo>;
79     using FpDelta = std::pair<int, uint32_t>;
80     using Func2FpDelta = std::unordered_map<uintptr_t, FpDelta>; // value: fpDelta & funcSize
81     using ConstInfo = std::vector<IntType>;
82     using DeoptInfoType = std::vector<std::variant<IntType, LargeInt, DwarfRegAndOffsetType>>;
83     using Pc2Deopt = std::unordered_map<uintptr_t, DeoptInfoType>;
84 
85     static constexpr size_t STACKMAP_ALIGN_BYTES = 2;
86     static constexpr size_t STACKMAP_PAIR_SIZE = 2;
87     static constexpr KindType CONSTANT_TYPE = 0;
88     static constexpr KindType OFFSET_TYPE = 1;
89     static constexpr uint16_t INVALID_DWARF_REG = 0;
90 
91     template <typename T>
EncodeData(std::vector<uint8_t> & outData,size_t & dataSize,T value)92     static void EncodeData(std::vector<uint8_t> &outData, size_t &dataSize, T value)
93     {
94         static_assert(std::is_signed_v<T>, "T must be signed");
95         SLeb128Type data = value;
96         size_t valueSize = panda::leb128::SignedEncodingSize(data);
97         outData.resize(valueSize);
98         dataSize = panda::leb128::EncodeSigned(data, outData.data());
99     }
100 
101     static bool IsBaseEqualDerive(SLeb128Type regOffset);
102     static LLVMStackMapType::OffsetType GetOffsetFromRegOff(SLeb128Type regOffset);
103     static void EncodeRegAndOffset(std::vector<uint8_t> &regOffset, size_t &regOffsetSize,
104         DwarfRegType reg, OffsetType offset, Triple triple, bool isBaseDerivedEq = false);
105     static bool DecodeRegAndOffset(SLeb128Type regOffset, DwarfRegType &reg, OffsetType &offset);
106     static void EncodeVRegsInfo(std::vector<uint8_t> &vregsInfo, size_t &vregsInfoSize,
107         VRegId id, LocationTy::Kind kind);
108     static void DecodeVRegsInfo(SLeb128Type vregsInfo, VRegId &id, KindType &kind);
109 
110 private:
111     static constexpr size_t STACKMAP_TYPE_NUM = 2;
112     static constexpr size_t STACKMAP_OFFSET_MUL = 8;
113     static constexpr size_t STACKMAP_OFFSET_EXP = 3; // 2^3 = 8
114     static constexpr RegType FP_VALUE = 0;
115     static constexpr RegType SP_VALUE = 1;
116     static constexpr KindType NO_DERIVED = 2;
117     static constexpr size_t STACKMAP_OFFSET_MASK = ~0x7LL;
118 };
119 
120 struct Header {
121     uint8_t  stackmapversion; // Stack Map Version (current version is 3)
122     uint8_t  reserved0; // Reserved (expected to be 0)
123     uint16_t reserved1; // Reserved (expected to be 0)
PrintHeader124     void Print() const
125     {
126         LOG_COMPILER(DEBUG) << "----- head ----";
127         LOG_COMPILER(DEBUG) << "   version:" << static_cast<int>(stackmapversion);
128         LOG_COMPILER(DEBUG) << "+++++ head ++++";
129     }
130 };
131 
132 #pragma pack(1)
133 struct StkMapSizeRecordTy {
134     uintptr_t functionAddress;
135     uint64_t stackSize;
136     uint64_t recordCount;
PrintStkMapSizeRecordTy137     void Print() const
138     {
139         LOG_COMPILER(DEBUG) << "               functionAddress:0x" << std::hex << functionAddress;
140         LOG_COMPILER(DEBUG) << "               stackSize:0x" << std::hex << stackSize;
141         LOG_COMPILER(DEBUG) << "               recordCount:" << std::hex << recordCount;
142     }
143 };
144 #pragma pack()
145 
146 struct ConstantsTy {
147     uintptr_t largeConstant;
PrintConstantsTy148     void Print() const
149     {
150         LOG_COMPILER(DEBUG) << "               LargeConstant:0x" << std::hex << largeConstant;
151     }
152 };
153 
154 struct StkMapRecordHeadTy {
155     uint64_t patchPointID;
156     uint32_t instructionOffset;
157     uint16_t reserved;
158     uint16_t numLocations;
PrintStkMapRecordHeadTy159     void Print() const
160     {
161         LOG_COMPILER(DEBUG) << "               PatchPointID:0x" << std::hex << patchPointID;
162         LOG_COMPILER(DEBUG) << "               instructionOffset:0x" << std::hex << instructionOffset;
163         LOG_COMPILER(DEBUG) << "               Reserved:0x" << std::hex << reserved;
164         LOG_COMPILER(DEBUG) << "               NumLocations:0x" << std::hex << numLocations;
165     }
166 };
167 struct LiveOutsTy {
168     LLVMStackMapType::DwarfRegType dwarfRegNum;
169     uint8_t reserved;
170     uint8_t sizeinBytes;
PrintLiveOutsTy171     void Print() const
172     {
173         LOG_COMPILER(DEBUG) << "                  Dwarf RegNum:" << dwarfRegNum;
174         LOG_COMPILER(DEBUG) << "                  Reserved:" << reserved;
175         LOG_COMPILER(DEBUG) << "                  SizeinBytes:" << sizeinBytes;
176     }
177 };
178 struct StkMapRecordTy {
179     struct StkMapRecordHeadTy head;
180     std::vector<struct LocationTy> locations;
181     std::vector<struct LiveOutsTy> liveOuts;
PrintStkMapRecordTy182     void Print() const
183     {
184         head.Print();
185         auto size = locations.size();
186         for (size_t i = 0; i < size; i++) {
187             LOG_COMPILER(DEBUG) << "                   #" << std::dec << i << ":";
188             locations[i].Print();
189         }
190         size = liveOuts.size();
191         for (size_t i = 0; i < size; i++) {
192             LOG_COMPILER(DEBUG) << "               liveOuts[" << i << "] info:";
193         }
194     }
195 };
196 
197 class DataInfo {
198 public:
DataInfo(std::unique_ptr<uint8_t[]> data)199     explicit DataInfo(std::unique_ptr<uint8_t[]> data): data_(std::move(data)), offset_(0) {}
~DataInfo()200     ~DataInfo()
201     {
202         data_.reset();
203         offset_ = 0;
204     }
205     template<class T>
Read()206     T Read()
207     {
208         T t = *reinterpret_cast<const T*>(data_.get() + offset_);
209         offset_ += sizeof(T);
210         return t;
211     }
GetOffset()212     unsigned int GetOffset() const
213     {
214         return offset_;
215     }
216 private:
217     std::unique_ptr<uint8_t[]> data_ {nullptr};
218     unsigned int offset_ {0};
219 };
220 
221 struct LLVMStackMap {
222     struct Header head;
223     std::vector<struct StkMapSizeRecordTy> stkSizeRecords;
224     std::vector<struct ConstantsTy> constants;
225     std::vector<struct StkMapRecordTy> stkMapRecord;
PrintLLVMStackMap226     void Print() const
227     {
228         head.Print();
229         for (size_t i = 0; i < stkSizeRecords.size(); i++) {
230             LOG_COMPILER(DEBUG) << "StkSizeRecord[" << i << "] info:";
231             stkSizeRecords[i].Print();
232         }
233         for (size_t i = 0; i < constants.size(); i++) {
234             LOG_COMPILER(DEBUG) << "Constants[" << i << "] info:";
235             constants[i].Print();
236         }
237         for (size_t i = 0; i < stkMapRecord.size(); i++) {
238             LOG_COMPILER(DEBUG) << "StkMapRecord[" << i << "] info:";
239             stkMapRecord[i].Print();
240         }
241     }
242 };
243 
244 class LLVMStackMapInfo : public CGStackMapInfo {
245 public:
LLVMStackMapInfo()246     LLVMStackMapInfo() : CGStackMapInfo() {}
247     ~LLVMStackMapInfo() = default;
248 
GetCallSiteInfoVec()249     const std::vector<LLVMStackMapType::Pc2CallSiteInfo> &GetCallSiteInfoVec() const
250     {
251         return pc2CallSiteInfoVec_;
252     }
253 
GetDeoptInfoVec()254     const std::vector<LLVMStackMapType::Pc2Deopt> &GetDeoptInfoVec() const
255     {
256         return pc2DeoptVec_;
257     }
258 
AppendCallSiteInfo(const LLVMStackMapType::Pc2CallSiteInfo & pc2CallSiteInfo)259     void AppendCallSiteInfo(const LLVMStackMapType::Pc2CallSiteInfo &pc2CallSiteInfo)
260     {
261         pc2CallSiteInfoVec_.push_back(pc2CallSiteInfo);
262     }
263 
AppendDeoptInfo(const LLVMStackMapType::Pc2Deopt & pc2DeoptInfo)264     void AppendDeoptInfo(const LLVMStackMapType::Pc2Deopt &pc2DeoptInfo)
265     {
266         pc2DeoptVec_.push_back(pc2DeoptInfo);
267     }
268 
PopCallSiteInfo()269     void PopCallSiteInfo()
270     {
271         pc2CallSiteInfoVec_.pop_back();
272     }
273 
PopDeoptInfo()274     void PopDeoptInfo()
275     {
276         pc2DeoptVec_.pop_back();
277     }
278 
GetStackMapKind()279     CGStackMapKind GetStackMapKind() const override
280     {
281         return kLLVMStackMapInfo;
282     }
283 
284 private:
285     std::vector<LLVMStackMapType::Pc2CallSiteInfo> pc2CallSiteInfoVec_;
286     std::vector<LLVMStackMapType::Pc2Deopt> pc2DeoptVec_;
287 };
288 } // namespace panda::ecmascript::kungfu
289 #endif  // ECMASCRIPT_LLVM_STACKMAP_TYPE_H