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> ®Offset, size_t ®OffsetSize, 104 DwarfRegType reg, OffsetType offset, Triple triple, bool isBaseDerivedEq = false); 105 static bool DecodeRegAndOffset(SLeb128Type regOffset, DwarfRegType ®, 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