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 31 #include "libpandabase/utils/leb128.h" 32 33 namespace panda::ecmascript::kungfu { 34 struct LocationTy { 35 enum class Kind: uint8_t { 36 REGISTER = 1, 37 DIRECT = 2, 38 INDIRECT = 3, 39 CONSTANT = 4, 40 CONSTANTNDEX = 5, 41 }; 42 static constexpr int CONSTANT_FIRST_ELEMENT_INDEX = 3; 43 static constexpr int CONSTANT_DEOPT_CNT_INDEX = 2; 44 45 Kind location; 46 uint8_t reserved_0; 47 uint16_t locationSize; 48 uint16_t dwarfRegNum; 49 uint16_t reserved_1; 50 int32_t offsetOrSmallConstant; 51 52 std::string PUBLIC_API TypeToString(Kind loc) const; 53 PrintLocationTy54 void Print() const 55 { 56 LOG_COMPILER(DEBUG) << TypeToString(location); 57 LOG_COMPILER(DEBUG) << ", size:" << std::dec << locationSize; 58 LOG_COMPILER(DEBUG) << "\tDwarfRegNum:" << dwarfRegNum; 59 LOG_COMPILER(DEBUG) << "\t OffsetOrSmallConstant:" << offsetOrSmallConstant; 60 } 61 }; 62 63 class LLVMStackMapType { 64 public: 65 using OffsetType = int32_t; 66 using DwarfRegType = uint16_t; 67 using IntType = int32_t; 68 using LargeInt = int64_t; 69 using RegType = int8_t; 70 using KindType = int8_t; 71 using VRegId = int16_t; 72 using SLeb128Type = int64_t; 73 using DwarfRegAndOffsetType = std::pair<DwarfRegType, OffsetType>; 74 using CallSiteInfo = std::vector<DwarfRegAndOffsetType>; 75 using Fun2InfoType = std::pair<uintptr_t, DwarfRegAndOffsetType>; 76 using Pc2CallSiteInfo = std::unordered_map<uintptr_t, CallSiteInfo>; 77 using FpDelta = std::pair<int, uint32_t>; 78 using Func2FpDelta = std::unordered_map<uintptr_t, FpDelta>; // value: fpDelta & funcSize 79 using ConstInfo = std::vector<IntType>; 80 using DeoptInfoType = std::vector<std::variant<IntType, LargeInt, DwarfRegAndOffsetType>>; 81 using Pc2Deopt = std::unordered_map<uintptr_t, DeoptInfoType>; 82 83 static constexpr size_t STACKMAP_ALIGN_BYTES = 2; 84 static constexpr KindType CONSTANT_TYPE = 0; 85 static constexpr KindType OFFSET_TYPE = 1; 86 87 template <typename T> EncodeData(std::vector<uint8_t> & outData,size_t & dataSize,T value)88 static void EncodeData(std::vector<uint8_t> &outData, size_t &dataSize, T value) 89 { 90 static_assert(std::is_signed_v<T>, "T must be signed"); 91 SLeb128Type data = value; 92 size_t valueSize = panda::leb128::SignedEncodingSize(data); 93 outData.resize(valueSize); 94 dataSize = panda::leb128::EncodeSigned(data, outData.data()); 95 } 96 97 static void EncodeRegAndOffset(std::vector<uint8_t> ®Offset, size_t ®OffsetSize, 98 DwarfRegType reg, OffsetType offset, Triple triple); 99 static void DecodeRegAndOffset(SLeb128Type regOffset, DwarfRegType ®, OffsetType &offset); 100 static void EncodeVRegsInfo(std::vector<uint8_t> &vregsInfo, size_t &vregsInfoSize, 101 VRegId id, LocationTy::Kind kind); 102 static void DecodeVRegsInfo(SLeb128Type vregsInfo, VRegId &id, KindType &kind); 103 104 private: 105 static constexpr size_t STACKMAP_TYPE_NUM = 2; 106 static constexpr RegType FP_VALUE = 0; 107 static constexpr RegType SP_VALUE = 1; 108 }; 109 110 struct Header { 111 uint8_t stackmapversion; // Stack Map Version (current version is 3) 112 uint8_t reserved0; // Reserved (expected to be 0) 113 uint16_t reserved1; // Reserved (expected to be 0) PrintHeader114 void Print() const 115 { 116 LOG_COMPILER(DEBUG) << "----- head ----"; 117 LOG_COMPILER(DEBUG) << " version:" << static_cast<int>(stackmapversion); 118 LOG_COMPILER(DEBUG) << "+++++ head ++++"; 119 } 120 }; 121 122 #pragma pack(1) 123 struct StkMapSizeRecordTy { 124 uintptr_t functionAddress; 125 uint64_t stackSize; 126 uint64_t recordCount; PrintStkMapSizeRecordTy127 void Print() const 128 { 129 LOG_COMPILER(DEBUG) << " functionAddress:0x" << std::hex << functionAddress; 130 LOG_COMPILER(DEBUG) << " stackSize:0x" << std::hex << stackSize; 131 LOG_COMPILER(DEBUG) << " recordCount:" << std::hex << recordCount; 132 } 133 }; 134 #pragma pack() 135 136 struct ConstantsTy { 137 uintptr_t largeConstant; PrintConstantsTy138 void Print() const 139 { 140 LOG_COMPILER(DEBUG) << " LargeConstant:0x" << std::hex << largeConstant; 141 } 142 }; 143 144 struct StkMapRecordHeadTy { 145 uint64_t patchPointID; 146 uint32_t instructionOffset; 147 uint16_t reserved; 148 uint16_t numLocations; PrintStkMapRecordHeadTy149 void Print() const 150 { 151 LOG_COMPILER(DEBUG) << " PatchPointID:0x" << std::hex << patchPointID; 152 LOG_COMPILER(DEBUG) << " instructionOffset:0x" << std::hex << instructionOffset; 153 LOG_COMPILER(DEBUG) << " Reserved:0x" << std::hex << reserved; 154 LOG_COMPILER(DEBUG) << " NumLocations:0x" << std::hex << numLocations; 155 } 156 }; 157 struct LiveOutsTy { 158 LLVMStackMapType::DwarfRegType dwarfRegNum; 159 uint8_t reserved; 160 uint8_t sizeinBytes; PrintLiveOutsTy161 void Print() const 162 { 163 LOG_COMPILER(DEBUG) << " Dwarf RegNum:" << dwarfRegNum; 164 LOG_COMPILER(DEBUG) << " Reserved:" << reserved; 165 LOG_COMPILER(DEBUG) << " SizeinBytes:" << sizeinBytes; 166 } 167 }; 168 struct StkMapRecordTy { 169 struct StkMapRecordHeadTy head; 170 std::vector<struct LocationTy> locations; 171 std::vector<struct LiveOutsTy> liveOuts; PrintStkMapRecordTy172 void Print() const 173 { 174 head.Print(); 175 auto size = locations.size(); 176 for (size_t i = 0; i < size; i++) { 177 LOG_COMPILER(DEBUG) << " #" << std::dec << i << ":"; 178 locations[i].Print(); 179 } 180 size = liveOuts.size(); 181 for (size_t i = 0; i < size; i++) { 182 LOG_COMPILER(DEBUG) << " liveOuts[" << i << "] info:"; 183 } 184 } 185 }; 186 187 class DataInfo { 188 public: DataInfo(std::unique_ptr<uint8_t[]> data)189 explicit DataInfo(std::unique_ptr<uint8_t[]> data): data_(std::move(data)), offset_(0) {} ~DataInfo()190 ~DataInfo() 191 { 192 data_.reset(); 193 offset_ = 0; 194 } 195 template<class T> Read()196 T Read() 197 { 198 T t = *reinterpret_cast<const T*>(data_.get() + offset_); 199 offset_ += sizeof(T); 200 return t; 201 } GetOffset()202 unsigned int GetOffset() const 203 { 204 return offset_; 205 } 206 private: 207 std::unique_ptr<uint8_t[]> data_ {nullptr}; 208 unsigned int offset_ {0}; 209 }; 210 211 struct LLVMStackMap { 212 struct Header head; 213 std::vector<struct StkMapSizeRecordTy> stkSizeRecords; 214 std::vector<struct ConstantsTy> constants; 215 std::vector<struct StkMapRecordTy> stkMapRecord; PrintLLVMStackMap216 void Print() const 217 { 218 head.Print(); 219 for (size_t i = 0; i < stkSizeRecords.size(); i++) { 220 LOG_COMPILER(DEBUG) << "StkSizeRecord[" << i << "] info:"; 221 stkSizeRecords[i].Print(); 222 } 223 for (size_t i = 0; i < constants.size(); i++) { 224 LOG_COMPILER(DEBUG) << "Constants[" << i << "] info:"; 225 constants[i].Print(); 226 } 227 for (size_t i = 0; i < stkMapRecord.size(); i++) { 228 LOG_COMPILER(DEBUG) << "StkMapRecord[" << i << "] info:"; 229 stkMapRecord[i].Print(); 230 } 231 } 232 }; 233 } // namespace panda::ecmascript::kungfu 234 #endif // ECMASCRIPT_LLVM_STACKMAP_TYPE_H