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> ®Offset, size_t ®OffsetSize, 101 DwarfRegType reg, OffsetType offset, Triple triple); 102 static void DecodeRegAndOffset(SLeb128Type regOffset, DwarfRegType ®, 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