• 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 KindType CONSTANT_TYPE = 0;
87     static constexpr KindType OFFSET_TYPE = 1;
88     static constexpr uint16_t INVALID_DWARF_REG = 0;
89 
90     template <typename T>
EncodeData(std::vector<uint8_t> & outData,size_t & dataSize,T value)91     static void EncodeData(std::vector<uint8_t> &outData, size_t &dataSize, T value)
92     {
93         static_assert(std::is_signed_v<T>, "T must be signed");
94         SLeb128Type data = value;
95         size_t valueSize = panda::leb128::SignedEncodingSize(data);
96         outData.resize(valueSize);
97         dataSize = panda::leb128::EncodeSigned(data, outData.data());
98     }
99 
100     static void EncodeRegAndOffset(std::vector<uint8_t> &regOffset, size_t &regOffsetSize,
101         DwarfRegType reg, OffsetType offset, Triple triple);
102     static void DecodeRegAndOffset(SLeb128Type regOffset, DwarfRegType &reg, OffsetType &offset);
103     static void EncodeVRegsInfo(std::vector<uint8_t> &vregsInfo, size_t &vregsInfoSize,
104         VRegId id, LocationTy::Kind kind);
105     static void DecodeVRegsInfo(SLeb128Type vregsInfo, VRegId &id, KindType &kind);
106 
107 private:
108     static constexpr size_t STACKMAP_TYPE_NUM = 2;
109     static constexpr RegType FP_VALUE = 0;
110     static constexpr RegType SP_VALUE = 1;
111 };
112 
113 struct Header {
114     uint8_t  stackmapversion; // Stack Map Version (current version is 3)
115     uint8_t  reserved0; // Reserved (expected to be 0)
116     uint16_t reserved1; // Reserved (expected to be 0)
PrintHeader117     void Print() const
118     {
119         LOG_COMPILER(DEBUG) << "----- head ----";
120         LOG_COMPILER(DEBUG) << "   version:" << static_cast<int>(stackmapversion);
121         LOG_COMPILER(DEBUG) << "+++++ head ++++";
122     }
123 };
124 
125 #pragma pack(1)
126 struct StkMapSizeRecordTy {
127     uintptr_t functionAddress;
128     uint64_t stackSize;
129     uint64_t recordCount;
PrintStkMapSizeRecordTy130     void Print() const
131     {
132         LOG_COMPILER(DEBUG) << "               functionAddress:0x" << std::hex << functionAddress;
133         LOG_COMPILER(DEBUG) << "               stackSize:0x" << std::hex << stackSize;
134         LOG_COMPILER(DEBUG) << "               recordCount:" << std::hex << recordCount;
135     }
136 };
137 #pragma pack()
138 
139 struct ConstantsTy {
140     uintptr_t largeConstant;
PrintConstantsTy141     void Print() const
142     {
143         LOG_COMPILER(DEBUG) << "               LargeConstant:0x" << std::hex << largeConstant;
144     }
145 };
146 
147 struct StkMapRecordHeadTy {
148     uint64_t patchPointID;
149     uint32_t instructionOffset;
150     uint16_t reserved;
151     uint16_t numLocations;
PrintStkMapRecordHeadTy152     void Print() const
153     {
154         LOG_COMPILER(DEBUG) << "               PatchPointID:0x" << std::hex << patchPointID;
155         LOG_COMPILER(DEBUG) << "               instructionOffset:0x" << std::hex << instructionOffset;
156         LOG_COMPILER(DEBUG) << "               Reserved:0x" << std::hex << reserved;
157         LOG_COMPILER(DEBUG) << "               NumLocations:0x" << std::hex << numLocations;
158     }
159 };
160 struct LiveOutsTy {
161     LLVMStackMapType::DwarfRegType dwarfRegNum;
162     uint8_t reserved;
163     uint8_t sizeinBytes;
PrintLiveOutsTy164     void Print() const
165     {
166         LOG_COMPILER(DEBUG) << "                  Dwarf RegNum:" << dwarfRegNum;
167         LOG_COMPILER(DEBUG) << "                  Reserved:" << reserved;
168         LOG_COMPILER(DEBUG) << "                  SizeinBytes:" << sizeinBytes;
169     }
170 };
171 struct StkMapRecordTy {
172     struct StkMapRecordHeadTy head;
173     std::vector<struct LocationTy> locations;
174     std::vector<struct LiveOutsTy> liveOuts;
PrintStkMapRecordTy175     void Print() const
176     {
177         head.Print();
178         auto size = locations.size();
179         for (size_t i = 0; i < size; i++) {
180             LOG_COMPILER(DEBUG) << "                   #" << std::dec << i << ":";
181             locations[i].Print();
182         }
183         size = liveOuts.size();
184         for (size_t i = 0; i < size; i++) {
185             LOG_COMPILER(DEBUG) << "               liveOuts[" << i << "] info:";
186         }
187     }
188 };
189 
190 class DataInfo {
191 public:
DataInfo(std::unique_ptr<uint8_t[]> data)192     explicit DataInfo(std::unique_ptr<uint8_t[]> data): data_(std::move(data)), offset_(0) {}
~DataInfo()193     ~DataInfo()
194     {
195         data_.reset();
196         offset_ = 0;
197     }
198     template<class T>
Read()199     T Read()
200     {
201         T t = *reinterpret_cast<const T*>(data_.get() + offset_);
202         offset_ += sizeof(T);
203         return t;
204     }
GetOffset()205     unsigned int GetOffset() const
206     {
207         return offset_;
208     }
209 private:
210     std::unique_ptr<uint8_t[]> data_ {nullptr};
211     unsigned int offset_ {0};
212 };
213 
214 struct LLVMStackMap {
215     struct Header head;
216     std::vector<struct StkMapSizeRecordTy> stkSizeRecords;
217     std::vector<struct ConstantsTy> constants;
218     std::vector<struct StkMapRecordTy> stkMapRecord;
PrintLLVMStackMap219     void Print() const
220     {
221         head.Print();
222         for (size_t i = 0; i < stkSizeRecords.size(); i++) {
223             LOG_COMPILER(DEBUG) << "StkSizeRecord[" << i << "] info:";
224             stkSizeRecords[i].Print();
225         }
226         for (size_t i = 0; i < constants.size(); i++) {
227             LOG_COMPILER(DEBUG) << "Constants[" << i << "] info:";
228             constants[i].Print();
229         }
230         for (size_t i = 0; i < stkMapRecord.size(); i++) {
231             LOG_COMPILER(DEBUG) << "StkMapRecord[" << i << "] info:";
232             stkMapRecord[i].Print();
233         }
234     }
235 };
236 
237 class LLVMStackMapInfo : public CGStackMapInfo {
238 public:
LLVMStackMapInfo()239     LLVMStackMapInfo() : CGStackMapInfo() {}
240     ~LLVMStackMapInfo() = default;
241 
GetCallSiteInfoVec()242     const std::vector<LLVMStackMapType::Pc2CallSiteInfo> &GetCallSiteInfoVec() const
243     {
244         return pc2CallSiteInfoVec_;
245     }
246 
GetDeoptInfoVec()247     const std::vector<LLVMStackMapType::Pc2Deopt> &GetDeoptInfoVec() const
248     {
249         return pc2DeoptVec_;
250     }
251 
AppendCallSiteInfo(const LLVMStackMapType::Pc2CallSiteInfo & pc2CallSiteInfo)252     void AppendCallSiteInfo(const LLVMStackMapType::Pc2CallSiteInfo &pc2CallSiteInfo)
253     {
254         pc2CallSiteInfoVec_.push_back(pc2CallSiteInfo);
255     }
256 
AppendDeoptInfo(const LLVMStackMapType::Pc2Deopt & pc2DeoptInfo)257     void AppendDeoptInfo(const LLVMStackMapType::Pc2Deopt &pc2DeoptInfo)
258     {
259         pc2DeoptVec_.push_back(pc2DeoptInfo);
260     }
261 
PopCallSiteInfo()262     void PopCallSiteInfo()
263     {
264         pc2CallSiteInfoVec_.pop_back();
265     }
266 
PopDeoptInfo()267     void PopDeoptInfo()
268     {
269         pc2DeoptVec_.pop_back();
270     }
271 
GetStackMapKind()272     CGStackMapKind GetStackMapKind() const override
273     {
274         return kLLVMStackMapInfo;
275     }
276 
277 private:
278     std::vector<LLVMStackMapType::Pc2CallSiteInfo> pc2CallSiteInfoVec_;
279     std::vector<LLVMStackMapType::Pc2Deopt> pc2DeoptVec_;
280 };
281 } // namespace panda::ecmascript::kungfu
282 #endif  // ECMASCRIPT_LLVM_STACKMAP_TYPE_H