1 /* 2 * Copyright (c) 2021 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 16 #ifndef ECMASCRIPT_COMPILER_LLVM_LLVMSTACKPARSE_H 17 #define ECMASCRIPT_COMPILER_LLVM_LLVMSTACKPARSE_H 18 19 #include <iostream> 20 #include <memory> 21 #include <tuple> 22 #include <unordered_map> 23 #include <vector> 24 #include "ecmascript/common.h" 25 #include "ecmascript/ecma_macros.h" 26 #include "ecmascript/interpreter/interpreter-inl.h" 27 28 namespace panda::ecmascript::kungfu { 29 using OffsetType = int32_t; 30 using DwarfRegType = uint16_t; 31 using DwarfRegAndOffsetType = std::pair<DwarfRegType, OffsetType>; 32 using CallSiteInfo = std::vector<DwarfRegAndOffsetType>; 33 using Fun2InfoType = std::pair<uintptr_t, DwarfRegAndOffsetType>; 34 35 struct Header { 36 uint8_t stackmapversion; // Stack Map Version (current version is 3) 37 uint8_t Reserved0; // Reserved (expected to be 0) 38 uint16_t Reserved1; // Reserved (expected to be 0) PrintHeader39 void Print() const 40 { 41 LOG_ECMA(DEBUG) << "----- head ----"; 42 LOG_ECMA(DEBUG) << " version:" << static_cast<int>(stackmapversion); 43 LOG_ECMA(DEBUG) << "+++++ head ++++"; 44 } 45 }; 46 47 #pragma pack(1) 48 struct StkSizeRecordTy { 49 uintptr_t functionAddress; 50 uint64_t stackSize; 51 uint64_t recordCount; PrintStkSizeRecordTy52 void Print() const 53 { 54 LOG_ECMA(DEBUG) << " functionAddress:0x" << std::hex << functionAddress; 55 LOG_ECMA(DEBUG) << " stackSize:0x" << std::hex << stackSize; 56 LOG_ECMA(DEBUG) << " recordCount:" << std::hex << recordCount; 57 } 58 }; 59 #pragma pack() 60 61 struct ConstantsTy { 62 uintptr_t LargeConstant; PrintConstantsTy63 void Print() const 64 { 65 LOG_ECMA(DEBUG) << " LargeConstant:0x" << std::hex << LargeConstant; 66 } 67 }; 68 69 struct StkMapRecordHeadTy { 70 uint64_t PatchPointID; 71 uint32_t InstructionOffset; 72 uint16_t Reserved; 73 uint16_t NumLocations; PrintStkMapRecordHeadTy74 void Print() const 75 { 76 LOG_ECMA(DEBUG) << " PatchPointID:0x" << std::hex << PatchPointID; 77 LOG_ECMA(DEBUG) << " instructionOffset:0x" << std::hex << InstructionOffset; 78 LOG_ECMA(DEBUG) << " Reserved:0x" << std::hex << Reserved; 79 LOG_ECMA(DEBUG) << " NumLocations:0x" << std::hex << NumLocations; 80 } 81 }; 82 83 struct LocationTy { 84 enum class Kind: uint8_t { 85 REGISTER = 1, 86 DIRECT = 2, 87 INDIRECT = 3, 88 CONSTANT = 4, 89 CONSTANTNDEX = 5, 90 }; 91 Kind location; 92 uint8_t Reserved_0; 93 uint16_t LocationSize; 94 uint16_t DwarfRegNum; 95 uint16_t Reserved_1; 96 OffsetType OffsetOrSmallConstant; 97 98 std::string PUBLIC_API TypeToString(Kind loc) const; 99 PrintLocationTy100 void Print() const 101 { 102 LOG_ECMA(DEBUG) << TypeToString(location); 103 LOG_ECMA(DEBUG) << ", size:" << std::dec << LocationSize; 104 LOG_ECMA(DEBUG) << "\tDwarfRegNum:" << DwarfRegNum; 105 LOG_ECMA(DEBUG) << "\t OffsetOrSmallConstant:" << OffsetOrSmallConstant; 106 } 107 }; 108 109 struct LiveOutsTy { 110 DwarfRegType DwarfRegNum; 111 uint8_t Reserved; 112 uint8_t SizeinBytes; PrintLiveOutsTy113 void Print() const 114 { 115 LOG_ECMA(DEBUG) << " Dwarf RegNum:" << DwarfRegNum; 116 LOG_ECMA(DEBUG) << " Reserved:" << Reserved; 117 LOG_ECMA(DEBUG) << " SizeinBytes:" << SizeinBytes; 118 } 119 }; 120 121 struct StkMapRecordTy { 122 struct StkMapRecordHeadTy head; 123 std::vector<struct LocationTy> Locations; 124 std::vector<struct LiveOutsTy> LiveOuts; PrintStkMapRecordTy125 void Print() const 126 { 127 head.Print(); 128 auto size = Locations.size(); 129 for (size_t i = 0; i < size; i++) { 130 LOG_ECMA(DEBUG) << " #" << std::dec << i << ":"; 131 Locations[i].Print(); 132 } 133 size = LiveOuts.size(); 134 for (size_t i = 0; i < size; i++) { 135 LOG_ECMA(DEBUG) << " liveOuts[" << i << "] info:"; 136 } 137 } 138 }; 139 140 class DataInfo { 141 public: DataInfo(std::unique_ptr<uint8_t[]> data)142 explicit DataInfo(std::unique_ptr<uint8_t[]> data): data_(std::move(data)), offset_(0) {} ~DataInfo()143 ~DataInfo() 144 { 145 data_.reset(); 146 offset_ = 0; 147 } 148 template<class T> Read()149 T Read() 150 { 151 T t = *reinterpret_cast<const T*>(data_.get() + offset_); 152 offset_ += sizeof(T); 153 return t; 154 } GetOffset()155 unsigned int GetOffset() const 156 { 157 return offset_; 158 } 159 private: 160 std::unique_ptr<uint8_t[]> data_ {nullptr}; 161 unsigned int offset_ {0}; 162 }; 163 164 struct LLVMStackMap { 165 struct Header head; 166 std::vector<struct StkSizeRecordTy> StkSizeRecords; 167 std::vector<struct ConstantsTy> Constants; 168 std::vector<struct StkMapRecordTy> StkMapRecord; PrintLLVMStackMap169 void Print() const 170 { 171 head.Print(); 172 for (size_t i = 0; i < StkSizeRecords.size(); i++) { 173 LOG_ECMA(DEBUG) << "stkSizeRecord[" << i << "] info:"; 174 StkSizeRecords[i].Print(); 175 } 176 for (size_t i = 0; i < Constants.size(); i++) { 177 LOG_ECMA(DEBUG) << "constants[" << i << "] info:"; 178 Constants[i].Print(); 179 } 180 for (size_t i = 0; i < StkMapRecord.size(); i++) { 181 LOG_ECMA(DEBUG) << "StkMapRecord[" << i << "] info:"; 182 StkMapRecord[i].Print(); 183 } 184 } 185 }; 186 187 class LLVMStackMapParser { 188 public: GetInstance()189 static LLVMStackMapParser& GetInstance() 190 { 191 static LLVMStackMapParser instance; 192 return instance; 193 } 194 bool PUBLIC_API CalculateStackMap(std::unique_ptr<uint8_t []> stackMapAddr); 195 bool PUBLIC_API CalculateStackMap(std::unique_ptr<uint8_t []> stackMapAddr, 196 uintptr_t hostCodeSectionAddr, uintptr_t deviceCodeSectionAddr); Print()197 void PUBLIC_API Print() const 198 { 199 llvmStackMap_.Print(); 200 } 201 const CallSiteInfo *GetCallSiteInfoByPc(uintptr_t funcAddr) const; 202 bool CollectStackMapSlots(uintptr_t callSiteAddr, uintptr_t frameFp, std::set<uintptr_t> &baseSet, 203 ChunkMap<DerivedDataKey, uintptr_t> *data, [[maybe_unused]] bool isVerifying) const; 204 bool CollectStackMapSlots(OptimizedLeaveFrame *frame, std::set<uintptr_t> &baseSet, 205 ChunkMap<DerivedDataKey, uintptr_t> *data, 206 [[maybe_unused]] bool isVerifying) const; 207 208 private: LLVMStackMapParser()209 LLVMStackMapParser() 210 { 211 stackMapAddr_ = nullptr; 212 pc2CallSiteInfo_.clear(); 213 pid2CallSiteInfo_.clear(); 214 dataInfo_ = nullptr; 215 } ~LLVMStackMapParser()216 ~LLVMStackMapParser() 217 { 218 if (stackMapAddr_) { 219 stackMapAddr_.release(); 220 } 221 pc2CallSiteInfo_.clear(); 222 pid2CallSiteInfo_.clear(); 223 dataInfo_ = nullptr; 224 } 225 void CalcCallSite(); 226 bool IsDeriveredPointer(int callsitetime) const; 227 const CallSiteInfo* GetCallSiteInfoByPatchID(uint64_t patchPointId) const; 228 void PrintCallSiteInfo(const CallSiteInfo *infos, OptimizedLeaveFrame *frame) const; 229 void PrintCallSiteInfo(const CallSiteInfo *infos, uintptr_t *fp) const; 230 std::unique_ptr<uint8_t[]> stackMapAddr_; 231 struct LLVMStackMap llvmStackMap_; 232 std::unordered_map<uintptr_t, CallSiteInfo> pc2CallSiteInfo_; 233 std::unordered_map<uint64_t, CallSiteInfo> pid2CallSiteInfo_; 234 [[maybe_unused]] std::unique_ptr<DataInfo> dataInfo_; 235 }; 236 } // namespace panda::ecmascript::kungfu 237 #endif // ECMASCRIPT_COMPILER_LLVM_LLVMSTACKPARSE_H