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#include "ecmascript/stackmap/llvm/llvm_stackmap_parser.h" 16 17using namespace panda::ecmascript; 18 19namespace panda::ecmascript::kungfu { 20std::string LocationTy::TypeToString(Kind loc) const 21{ 22 switch (loc) { 23 case Kind::REGISTER: 24 return "Register Reg Value in a register"; 25 case Kind::DIRECT: 26 return "Direct Reg + Offset Frame index value"; 27 case Kind::INDIRECT: 28 return "Indirect [Reg + Offset] Spilled value"; 29 case Kind::CONSTANT: 30 return "Constant Offset Small constant"; 31 case Kind::CONSTANTNDEX: 32 return "ConstIndex constants[Offset] Large constant"; 33 default: 34 return "no know location"; 35 } 36} 37 38void LLVMStackMapParser::FilterCallSiteInfo(LLVMStackMapType::CallSiteInfo &info) 39{ 40 ASSERT(GC_PAIR_SIZE == 2); // 2 : The expected value of GC_PAIR_SIZE is 2 41 ASSERT(info.size() % GC_PAIR_SIZE == 0); 42 for (auto it = info.begin(); it != info.end();) { 43 auto base = it; 44 auto deri = ++it; 45 bool baseIsConst = (base->first == LLVMStackMapType::INVALID_DWARF_REG); 46 bool deriIsConst = (deri->first == LLVMStackMapType::INVALID_DWARF_REG); 47 if (baseIsConst && deriIsConst) { 48 it = info.erase(base, base + GC_PAIR_SIZE); 49 } else if (baseIsConst && !deriIsConst) { 50 base->first = deri->first; 51 base->second = deri->second; 52 it++; 53 } else if (!baseIsConst && deriIsConst) { 54 deri->first = base->first; 55 deri->second = base->second; 56 it++; 57 } else { 58 it++; 59 } 60 } 61 ASSERT(info.size() % GC_PAIR_SIZE == 0); 62} 63 64void LLVMStackMapParser::CalcCallSite() 65{ 66 uint64_t recordNum = 0; 67 LLVMStackMapType::Pc2CallSiteInfo pc2CallSiteInfo; 68 LLVMStackMapType::Pc2Deopt deoptbundles; 69 70 auto calStkMapRecordFunc = [this, &recordNum, &pc2CallSiteInfo, &deoptbundles](uintptr_t address, 71 uint32_t recordId) { 72 struct StkMapRecordTy &record = llvmStackMap_.stkMapRecord[recordNum + recordId]; 73 struct StkMapRecordHeadTy &recordHead = record.head; 74 uint32_t instructionOffset = recordHead.instructionOffset; 75 uintptr_t pc = address + instructionOffset; 76 uint64_t pID = recordHead.patchPointID; 77 78 if (pc2CallSiteInfo.find(pc) == pc2CallSiteInfo.end()) { 79 auto p = std::pair<uintptr_t, LLVMStackMapType::CallSiteInfo>(pc, {}); 80 pc2CallSiteInfo.insert(p); 81 } 82 LLVMStackMapType::CallSiteInfo& callSiteInfo = pc2CallSiteInfo.find(pc)->second; 83 84 ASSERT(recordHead.numLocations > LocationTy::CONSTANT_DEOPT_CNT_INDEX); 85 const int lastDeoptIndex = record.locations[LocationTy::CONSTANT_DEOPT_CNT_INDEX].offsetOrSmallConstant + 86 LocationTy::CONSTANT_DEOPT_CNT_INDEX; 87 88 for (int j = LocationTy::CONSTANT_FIRST_ELEMENT_INDEX; j < recordHead.numLocations; j++) { 89 const struct LocationTy &loc = record.locations[j]; 90 if (j <= lastDeoptIndex) { 91 switch (loc.location) { 92 case LocationTy::Kind::REGISTER: 93 case LocationTy::Kind::DIRECT: { 94 LOG_ECMA(FATAL) << "this branch is unreachable"; 95 UNREACHABLE(); 96 break; 97 } 98 case LocationTy::Kind::INDIRECT: { 99 OPTIONAL_LOG_COMPILER(DEBUG) << "DwarfRegNum:" << loc.dwarfRegNum 100 << " loc.OffsetOrSmallConstant:" << loc.offsetOrSmallConstant 101 << " address:" << address 102 << " instructionOffset:" << instructionOffset 103 << " callsite:" << " patchPointID :" << std::hex 104 << pID << pc; 105 LLVMStackMapType::DwarfRegAndOffsetType info(loc.dwarfRegNum, loc.offsetOrSmallConstant); 106 deoptbundles[pc].push_back(info); 107 break; 108 } 109 case LocationTy::Kind::CONSTANT: { 110 deoptbundles[pc].push_back(loc.offsetOrSmallConstant); 111 break; 112 } 113 case LocationTy::Kind::CONSTANTNDEX: { 114 auto v = llvmStackMap_.constants[loc.offsetOrSmallConstant].largeConstant; 115 deoptbundles[pc].push_back(static_cast<LLVMStackMapType::LargeInt>(v)); 116 break; 117 } 118 default: { 119 LOG_ECMA(FATAL) << "this branch is unreachable"; 120 UNREACHABLE(); 121 break; 122 } 123 } 124 } else { 125 switch (loc.location) { 126 case LocationTy::Kind::REGISTER: 127 case LocationTy::Kind::DIRECT: { 128 LOG_ECMA(FATAL) << "this branch is unreachable"; 129 UNREACHABLE(); 130 break; 131 } 132 case LocationTy::Kind::INDIRECT: 133 case LocationTy::Kind::CONSTANT: 134 case LocationTy::Kind::CONSTANTNDEX: { 135 OPTIONAL_LOG_COMPILER(DEBUG) << "DwarfRegNum:" << loc.dwarfRegNum 136 << " loc.OffsetOrSmallConstant:" << loc.offsetOrSmallConstant 137 << " address:" << address 138 << " instructionOffset:" << instructionOffset 139 << " callsite:" << " patchPointID :" << std::hex 140 << pID << pc; 141 uint16_t regNum = (loc.location == LocationTy::Kind::INDIRECT) 142 ? loc.dwarfRegNum 143 : LLVMStackMapType::INVALID_DWARF_REG; 144 int offset = (loc.location == LocationTy::Kind::INDIRECT) ? loc.offsetOrSmallConstant : 0; 145 LLVMStackMapType::DwarfRegAndOffsetType info(regNum, offset); 146 callSiteInfo.emplace_back(info); 147 break; 148 } 149 default: { 150 LOG_ECMA(FATAL) << "this branch is unreachable"; 151 UNREACHABLE(); 152 break; 153 } 154 } 155 } 156 } 157 FilterCallSiteInfo(callSiteInfo); 158 }; 159 160 const size_t count = llvmStackMap_.stkSizeRecords.size(); 161 for (size_t i = 0; i < count; i++) { 162 // relative offset 163 struct StkMapSizeRecordTy &sizeRec = llvmStackMap_.stkSizeRecords[i]; 164 uintptr_t address = sizeRec.functionAddress; 165 uint64_t recordCount = sizeRec.recordCount; 166 fun2RecordNum_.emplace_back(std::make_pair(address, recordCount)); 167 for (uint64_t k = 0; k < recordCount; k++) { 168 calStkMapRecordFunc(address, k); 169 } 170 recordNum += recordCount; 171 } 172 173 stackMapInfo.AppendCallSiteInfo(pc2CallSiteInfo); 174 stackMapInfo.AppendDeoptInfo(deoptbundles); 175} 176 177bool LLVMStackMapParser::CalculateStackMap(std::unique_ptr<uint8_t []> stackMapAddr) 178{ 179 if (!stackMapAddr) { 180 LOG_COMPILER(ERROR) << "stackMapAddr nullptr error ! "; 181 return false; 182 } 183 dataInfo_ = std::make_unique<DataInfo>(std::move(stackMapAddr)); 184 llvmStackMap_.head = dataInfo_->Read<struct Header>(); 185 uint32_t numFunctions, numConstants, numRecords; 186 numFunctions = dataInfo_->Read<uint32_t>(); 187 numConstants = dataInfo_->Read<uint32_t>(); 188 numRecords = dataInfo_->Read<uint32_t>(); 189 for (uint32_t i = 0; i < numFunctions; i++) { 190 auto stkRecord = dataInfo_->Read<struct StkMapSizeRecordTy>(); 191 llvmStackMap_.stkSizeRecords.push_back(stkRecord); 192 } 193 194 for (uint32_t i = 0; i < numConstants; i++) { 195 auto val = dataInfo_->Read<struct ConstantsTy>(); 196 llvmStackMap_.constants.push_back(val); 197 } 198 for (uint32_t i = 0; i < numRecords; i++) { 199 struct StkMapRecordTy stkSizeRecord; 200 auto head = dataInfo_->Read<struct StkMapRecordHeadTy>(); 201 stkSizeRecord.head = head; 202 for (uint16_t j = 0; j < head.numLocations; j++) { 203 auto location = dataInfo_->Read<struct LocationTy>(); 204 stkSizeRecord.locations.push_back(location); 205 } 206 while (dataInfo_->GetOffset() & 7) { // 7: 8 byte align 207 dataInfo_->Read<uint16_t>(); 208 } 209 uint32_t numLiveOuts = dataInfo_->Read<uint32_t>(); 210 if (numLiveOuts > 0) { 211 for (uint32_t j = 0; j < numLiveOuts; j++) { 212 auto liveOut = dataInfo_->Read<struct LiveOutsTy>(); 213 stkSizeRecord.liveOuts.push_back(liveOut); 214 } 215 } 216 while (dataInfo_->GetOffset() & 7) { // 7: 8 byte align 217 dataInfo_->Read<uint16_t>(); 218 } 219 llvmStackMap_.stkMapRecord.push_back(stkSizeRecord); 220 } 221 CalcCallSite(); 222 return true; 223} 224 225uint32_t ARKCallsite::CalHeadSize() const 226{ 227 uint32_t headSize = sizeof(head); 228 return headSize; 229} 230 231uint32_t ARKCallsite::CalStackMapSize(Triple triple) const 232{ 233 size_t stackmapSize = 0; 234 for (auto &x : stackmaps) { 235 std::vector<uint8_t> value; 236 size_t valueSize = 0; 237 LLVMStackMapType::EncodeRegAndOffset(value, valueSize, x.first, x.second, triple); 238 stackmapSize += value.size(); 239 } 240 return stackmapSize; 241} 242 243bool LLVMStackMapParser::CalculateStackMap(std::unique_ptr<uint8_t []> stackMapAddr, 244 uintptr_t hostCodeSectionAddr, uintptr_t hostCodeSectionOffset) 245{ 246 bool ret = CalculateStackMap(std::move(stackMapAddr)); 247 if (!ret) { 248 return false; 249 } 250 251 OPTIONAL_LOG_COMPILER(DEBUG) << "stackmap calculate update funcitonaddress "; 252 253 for (size_t i = 0; i < llvmStackMap_.stkSizeRecords.size(); i++) { 254 uintptr_t hostAddr = llvmStackMap_.stkSizeRecords[i].functionAddress; 255 uintptr_t offset = hostAddr - hostCodeSectionAddr + hostCodeSectionOffset; 256 llvmStackMap_.stkSizeRecords[i].functionAddress = offset; 257 OPTIONAL_LOG_COMPILER(DEBUG) << std::dec << i << "th function " << std::hex << hostAddr << " ---> " 258 << " offset:" << offset; 259 } 260 stackMapInfo.PopCallSiteInfo(); 261 stackMapInfo.PopDeoptInfo(); 262 fun2RecordNum_.clear(); 263 CalcCallSite(); 264 return true; 265} 266} // namespace panda::ecmascript::kungfu 267