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#include <map> 16 17#include "ecmascript/stackmap/ark_stackmap_builder.h" 18#include "ecmascript/stackmap/ark_stackmap_parser.h" 19#include "ecmascript/stackmap/litecg/litecg_stackmap_type.h" 20#include "ecmascript/stackmap/llvm/llvm_stackmap_parser.h" 21 22namespace panda::ecmascript::kungfu { 23void BinaryBufferWriter::WriteBuffer(const uint8_t *src, uint32_t count, bool flag) 24{ 25 uint8_t *dst = buffer_ + offset_; 26 if (flag) { 27 std::cout << "buffer_:0x" << std::hex << buffer_ << " offset_:0x" << offset_ << std::endl; 28 } 29 if (dst >= buffer_ && dst + count <= buffer_ + length_) { 30 if (memcpy_s(dst, buffer_ + length_ - dst, src, count) != EOK) { 31 LOG_FULL(FATAL) << "memcpy_s failed"; 32 return; 33 }; 34 offset_ = offset_ + count; 35 } else { 36 LOG_FULL(FATAL) << "parse buffer error, length is 0 or overflow"; 37 } 38} 39 40void ArkStackMapBuilder::Dump(const StackMapDumper& dumpInfo) const 41{ 42 LOG_COMPILER(INFO) << "total callsite num: " << dumpInfo.callsiteNum 43 << ", total ark stack map num: " << dumpInfo.stackmapNum 44 << ", total deopt num: " << dumpInfo.deoptNum; 45 double callsiteHeadsSize = static_cast<double>(dumpInfo.callsiteHeadSize); 46 double stackMapsSize = static_cast<double>(dumpInfo.arkStackMapSize); 47 double deoptsSize = static_cast<double>(dumpInfo.deoptSize); 48 LOG_COMPILER(INFO) << "total callsite head size: " 49 << std::fixed << std::setprecision(DECIMAL_LENS) 50 << (callsiteHeadsSize / 1_KB) << "KB, total stackmap size: " 51 << std::fixed << std::setprecision(DECIMAL_LENS) 52 << (stackMapsSize / 1_KB) << "KB, total deopt size: " 53 << std::fixed << std::setprecision(DECIMAL_LENS) 54 << (deoptsSize / 1_KB) << "KB"; 55} 56 57std::pair<std::shared_ptr<uint8_t>, uint32_t> ArkStackMapBuilder::Run(std::unique_ptr<uint8_t []> stackMapAddr, 58 uintptr_t hostCodeSectionAddr, Triple triple) 59{ 60 LLVMStackMapInfo stackMapInfo; 61 LLVMStackMapParser parser(stackMapInfo); 62 auto result = parser.CalculateStackMap(std::move(stackMapAddr), hostCodeSectionAddr, 0); 63 if (!result) { 64 LOG_ECMA(FATAL) << "this branch is unreachable"; 65 UNREACHABLE(); 66 } 67 std::pair<std::shared_ptr<uint8_t>, uint32_t> info = GenerateArkStackMap(stackMapInfo, triple); 68 return info; 69} 70 71void ArkStackMapBuilder::Collect( 72 std::unique_ptr<uint8_t []> stackMapAddr, 73 uintptr_t hostCodeSectionAddr, 74 uintptr_t hostCodeSectionOffset, 75 CGStackMapInfo &stackMapInfo) 76{ 77 LLVMStackMapInfo &llvmStackMapInfo = static_cast<LLVMStackMapInfo&>(stackMapInfo); 78 LLVMStackMapParser parser(llvmStackMapInfo); 79 auto result = parser.CalculateStackMap(std::move(stackMapAddr), hostCodeSectionAddr, hostCodeSectionOffset); 80 if (!result) { 81 LOG_ECMA(FATAL) << "this branch is unreachable"; 82 UNREACHABLE(); 83 } 84} 85 86std::pair<std::shared_ptr<uint8_t>, uint32_t> ArkStackMapBuilder::GenerateArkStackMap( 87 CGStackMapInfo &stackMapInfo, Triple triple) 88{ 89 ARKCallsiteAOTFileInfo AOTFileInfo; 90 GenArkCallsiteAOTFileInfo(stackMapInfo, AOTFileInfo, triple); 91 uint32_t secSize = AOTFileInfo.secHead.secSize; 92 uint8_t *p = new(std::nothrow) uint8_t[secSize]; 93 if (p == nullptr) { 94 LOG_FULL(FATAL) << "new secSize:0x" << std::hex << secSize << " failed"; 95 } 96 std::shared_ptr<uint8_t> ptr(p, [](uint8_t *p) { delete []p;}); 97 SaveArkCallsiteAOTFileInfo(ptr.get(), secSize, AOTFileInfo, triple); 98 if (traceStackMap_) { 99 Dump(dumper_); 100 } 101 return std::make_pair(ptr, secSize); 102} 103 104void ArkStackMapBuilder::SaveArkStackMap(const ARKCallsiteAOTFileInfo& info, BinaryBufferWriter& writer, Triple triple) 105{ 106 size_t n = info.callsites.size(); 107 for (size_t i = 0; i < n; i++) { 108 auto &callSite = info.callsites.at(i); 109 LLVMStackMapType::CallSiteInfo stackmaps = callSite.stackmaps; 110 size_t m = stackmaps.size(); 111 for (size_t j = 0; j < m; j++) { 112 auto &stackmap = stackmaps.at(j); 113 LLVMStackMapType::DwarfRegType reg = stackmap.first; 114 LLVMStackMapType::OffsetType offset = stackmap.second; 115 if (j == 0) { 116 ASSERT(callSite.head.stackmapOffsetInSMSec == writer.GetOffset()); 117 } 118 std::vector<uint8_t> regOffset; 119 size_t regOffsetSize = 0; 120 LLVMStackMapType::EncodeRegAndOffset(regOffset, regOffsetSize, reg, offset, triple); 121 writer.WriteBuffer(reinterpret_cast<const uint8_t *>(regOffset.data()), regOffset.size()); 122 dumper_.arkStackMapSize += regOffsetSize; 123 if (j == m - 1) { 124 ASSERT((callSite.head.stackmapOffsetInSMSec + callSite.CalStackMapSize(triple)) == writer.GetOffset()); 125 } 126 } 127 } 128 writer.AlignOffset(); 129} 130 131void ArkStackMapBuilder::SaveArkDeopt(const ARKCallsiteAOTFileInfo& info, BinaryBufferWriter& writer, Triple triple) 132{ 133 for (auto &it: info.callsites) { 134 auto& callsite2Deopt = it.callsite2Deopt; 135 size_t m = callsite2Deopt.size(); 136 for (size_t j = 0; j < m; j++) { 137 auto &deopt = callsite2Deopt.at(j); 138 if (j == 0) { 139 ASSERT(it.head.deoptOffset == writer.GetOffset()); 140 } 141 std::vector<uint8_t> vregsInfo; 142 size_t vregsInfoSize = 0; 143 LLVMStackMapType::EncodeVRegsInfo(vregsInfo, vregsInfoSize, deopt.id, deopt.kind); 144 writer.WriteBuffer(reinterpret_cast<const uint8_t *>(vregsInfo.data()), vregsInfoSize); 145 dumper_.deoptSize += vregsInfoSize; 146 auto& value = deopt.value; 147 if (std::holds_alternative<LLVMStackMapType::IntType>(value)) { 148 LLVMStackMapType::IntType v = std::get<LLVMStackMapType::IntType>(value); 149 std::vector<uint8_t> num; 150 size_t numSize = 0; 151 LLVMStackMapType::EncodeData(num, numSize, v); 152 writer.WriteBuffer(reinterpret_cast<const uint8_t *>(num.data()), numSize); 153 dumper_.deoptSize += numSize; 154 } else if (std::holds_alternative<LLVMStackMapType::LargeInt>(value)) { 155 LLVMStackMapType::LargeInt v = std::get<LLVMStackMapType::LargeInt>(value); 156 std::vector<uint8_t> num; 157 size_t numSize = 0; 158 LLVMStackMapType::EncodeData(num, numSize, v); 159 writer.WriteBuffer(reinterpret_cast<const uint8_t *>(num.data()), numSize); 160 dumper_.deoptSize += numSize; 161 } else if (std::holds_alternative<LLVMStackMapType::DwarfRegAndOffsetType>(value)) { 162 LLVMStackMapType::DwarfRegAndOffsetType v = std::get<LLVMStackMapType::DwarfRegAndOffsetType>(value); 163 std::vector<uint8_t> regOffset; 164 size_t regOffsetSize = 0; 165 LLVMStackMapType::EncodeRegAndOffset(regOffset, regOffsetSize, v.first, v.second, triple); 166 writer.WriteBuffer(reinterpret_cast<const uint8_t *>(regOffset.data()), regOffset.size()); 167 dumper_.arkStackMapSize += regOffsetSize; 168 } else { 169 LOG_ECMA(FATAL) << "this branch is unreachable"; 170 UNREACHABLE(); 171 } 172 } 173 } 174} 175 176void ArkStackMapBuilder::SaveArkCallsiteAOTFileInfo(uint8_t *ptr, uint32_t length, 177 const ARKCallsiteAOTFileInfo& info, Triple triple) 178{ 179 BinaryBufferWriter writer(ptr, length); 180 ASSERT(length >= info.secHead.secSize); 181 writer.WriteBuffer(reinterpret_cast<const uint8_t *>(&(info.secHead)), sizeof(ArkStackMapHeader)); 182 dumper_.callsiteHeadSize += sizeof(ArkStackMapHeader); 183 for (auto &it: info.callsites) { 184 writer.WriteBuffer(reinterpret_cast<const uint8_t *>(&(it.head)), sizeof(CallsiteHeader)); 185 dumper_.callsiteHeadSize += sizeof(CallsiteHeader); 186 } 187 SaveArkStackMap(info, writer, triple); 188 SaveArkDeopt(info, writer, triple); 189#ifndef NDEBUG 190 ArkStackMapParser parser; 191 parser.ParseArkStackMapAndDeopt(ptr, length); 192#endif 193} 194 195template <class Vec> 196void ArkStackMapBuilder::SortCallSite( 197 const std::vector<std::unordered_map<uintptr_t, Vec>> &infos, 198 std::vector<std::pair<uintptr_t, Vec>>& result) 199{ 200 for (auto &info: infos) { 201 for (auto &it: info) { 202 result.emplace_back(it); 203 } 204 } 205 std::sort(result.begin(), result.end(), 206 [](const std::pair<uintptr_t, Vec> &x, const std::pair<uintptr_t, Vec> &y) { 207 return x.first < y.first; 208 }); 209} 210 211void ArkStackMapBuilder::CalcCallsitePc(std::vector<std::pair<uintptr_t, LLVMStackMapType::DeoptInfoType>> &pc2Deopt, 212 std::vector<std::pair<uintptr_t, LLVMStackMapType::CallSiteInfo>> &pc2StackMap, std::vector<intptr_t> &callsitePcs) 213{ 214 std::set<uintptr_t> pcSet; 215 for (auto &it: pc2Deopt) { 216 pcSet.insert(it.first); 217 } 218 for (auto &it: pc2StackMap) { 219 pcSet.insert(it.first); 220 } 221 callsitePcs.assign(pcSet.begin(), pcSet.end()); 222} 223 224int ArkStackMapBuilder::FindLoc(std::vector<intptr_t> &CallsitePcs, intptr_t pc) 225{ 226 for (size_t i = 0; i < CallsitePcs.size(); i++) { 227 if (CallsitePcs[i] == pc) { 228 return i; 229 } 230 } 231 return -1; 232} 233 234void ArkStackMapBuilder::GenARKDeopt(const LLVMStackMapType::DeoptInfoType& deopt, std::pair<uint32_t, 235 std::vector<ARKDeopt>> &sizeAndArkDeopt, Triple triple) 236{ 237 ASSERT(deopt.size() % DEOPT_ENTRY_SIZE == 0); // 2:<id, value> 238 uint32_t total = 0; 239 ARKDeopt v; 240 for (size_t i = 0; i < deopt.size(); i += 2) { // 2:<id, value> 241 ASSERT(std::holds_alternative<LLVMStackMapType::IntType>(deopt[i])); 242 LLVMStackMapType::VRegId id = static_cast<LLVMStackMapType::VRegId>( 243 std::get<LLVMStackMapType::IntType>(deopt[i])); 244 v.id = id; 245 auto value = deopt[i + 1]; 246 if (std::holds_alternative<LLVMStackMapType::IntType>(value)) { 247 v.kind = LocationTy::Kind::CONSTANT; 248 v.value = std::get<LLVMStackMapType::IntType>(value); 249 std::vector<uint8_t> vregsInfo; 250 size_t vregsInfoSize = 0; 251 LLVMStackMapType::EncodeVRegsInfo(vregsInfo, vregsInfoSize, v.id, v.kind); 252 size_t valueSize = panda::leb128::SignedEncodingSize(std::get<LLVMStackMapType::IntType>(value)); 253 total += (vregsInfoSize + valueSize); 254 } else if (std::holds_alternative<LLVMStackMapType::LargeInt>(value)) { 255 v.kind = LocationTy::Kind::CONSTANTNDEX; 256 v.value = std::get<LLVMStackMapType::LargeInt>(value); 257 std::vector<uint8_t> vregsInfo; 258 size_t vregsInfoSize = 0; 259 LLVMStackMapType::EncodeVRegsInfo(vregsInfo, vregsInfoSize, v.id, v.kind); 260 size_t valueSize = panda::leb128::SignedEncodingSize(std::get<LLVMStackMapType::LargeInt>(value)); 261 total += (vregsInfoSize + valueSize); 262 } else if (std::holds_alternative<LLVMStackMapType::DwarfRegAndOffsetType>(value)) { 263 v.kind = LocationTy::Kind::INDIRECT; 264 v.value = std::get<LLVMStackMapType::DwarfRegAndOffsetType>(value); 265 std::vector<uint8_t> vregsInfo; 266 size_t vregsInfoSize = 0; 267 LLVMStackMapType::EncodeVRegsInfo(vregsInfo, vregsInfoSize, v.id, v.kind); 268 LLVMStackMapType::DwarfRegType reg = std::get<LLVMStackMapType::DwarfRegAndOffsetType>(value).first; 269 LLVMStackMapType::OffsetType offset = std::get<LLVMStackMapType::DwarfRegAndOffsetType>(value).second; 270 std::vector<uint8_t> regOffset; 271 size_t regOffsetSize = 0; 272 LLVMStackMapType::EncodeRegAndOffset(regOffset, regOffsetSize, reg, offset, triple); 273 total += (vregsInfoSize + regOffsetSize); 274 } else { 275 LOG_ECMA(FATAL) << "this branch is unreachable"; 276 UNREACHABLE(); 277 } 278 sizeAndArkDeopt.second.emplace_back(v); 279 } 280 std::sort(sizeAndArkDeopt.second.begin(), sizeAndArkDeopt.second.end(), 281 [](const ARKDeopt &a, const ARKDeopt &b) { 282 return a.id < b.id; 283 }); 284 sizeAndArkDeopt.first = total; 285} 286 287void ArkStackMapBuilder::GenArkCallsiteAOTFileInfo(const CGStackMapInfo &stackMapInfo, 288 ARKCallsiteAOTFileInfo &result, Triple triple) 289{ 290 std::vector<std::pair<uintptr_t, LLVMStackMapType::CallSiteInfo>> pc2StackMaps; 291 std::vector<std::pair<uintptr_t, LLVMStackMapType::DeoptInfoType>> pc2Deopts; 292 if (stackMapInfo.GetStackMapKind() == CGStackMapInfo::kLiteCGStackMapInfo) { 293 std::vector<LLVMStackMapType::Pc2CallSiteInfo> pc2StackMapsVec; 294 std::vector<LLVMStackMapType::Pc2Deopt> pc2DeoptInfoVec; 295 const auto &liteCGStackMapInfo = static_cast<const LiteCGStackMapInfo&>(stackMapInfo); 296 liteCGStackMapInfo.ConvertToLLVMStackMapInfo(pc2StackMapsVec, pc2DeoptInfoVec, triple); 297 SortCallSite(pc2StackMapsVec, pc2StackMaps); 298 SortCallSite(pc2DeoptInfoVec, pc2Deopts); 299 } else { 300 const auto &llvmStackMapInfo = static_cast<const LLVMStackMapInfo&>(stackMapInfo); 301 SortCallSite(llvmStackMapInfo.GetCallSiteInfoVec(), pc2StackMaps); 302 SortCallSite(llvmStackMapInfo.GetDeoptInfoVec(), pc2Deopts); 303 } 304 ARKCallsite callsite; 305 uint32_t secSize = 0; 306 307 std::vector<intptr_t> CallsitePcs; 308 309 CalcCallsitePc(pc2Deopts, pc2StackMaps, CallsitePcs); 310 uint32_t callsiteNum = CallsitePcs.size(); 311 dumper_.callsiteNum = callsiteNum; 312 result.callsites.resize(callsiteNum); 313 uint32_t stackmapOffset = sizeof(ArkStackMapHeader) + sizeof(CallsiteHeader) * callsiteNum; 314 for (auto &x: pc2StackMaps) { 315 LLVMStackMapType::CallSiteInfo i = x.second; 316 callsite.head.calliteOffsetInTxtSec = x.first; 317 ASSERT(std::numeric_limits<uint16_t>::min() <= i.size() && i.size() <= std::numeric_limits<uint16_t>::max()); 318 callsite.head.stackmapNum = i.size(); 319 callsite.head.stackmapOffsetInSMSec = stackmapOffset; 320 callsite.head.deoptOffset = 0; 321 callsite.head.deoptNum = 0; 322 callsite.stackmaps = i; 323 stackmapOffset += callsite.CalStackMapSize(triple); 324 int loc = FindLoc(CallsitePcs, x.first); 325 ASSERT(loc >= 0 && loc < static_cast<int>(callsiteNum)); 326 result.callsites[static_cast<uint32_t>(loc)] = callsite; 327 dumper_.stackmapNum += i.size(); 328 } 329 stackmapOffset = AlignUp(stackmapOffset, LLVMStackMapType::STACKMAP_ALIGN_BYTES); 330 secSize = stackmapOffset; 331 for (auto &x: pc2Deopts) { 332 int loc = FindLoc(CallsitePcs, x.first); 333 ASSERT(loc >= 0 && loc < static_cast<int>(callsiteNum)); 334 LLVMStackMapType::DeoptInfoType deopt = x.second; 335 result.callsites[static_cast<uint32_t>(loc)].head.calliteOffsetInTxtSec = x.first; 336 ASSERT(std::numeric_limits<uint16_t>::min() <= deopt.size() 337 && deopt.size() <= std::numeric_limits<uint16_t>::max()); 338 result.callsites[static_cast<uint32_t>(loc)].head.deoptNum = deopt.size(); 339 result.callsites[static_cast<uint32_t>(loc)].head.deoptOffset = secSize; 340 std::pair<uint32_t, std::vector<ARKDeopt>> sizeAndArkDeopt; 341 GenARKDeopt(deopt, sizeAndArkDeopt, triple); 342 secSize += sizeAndArkDeopt.first; 343 result.callsites[static_cast<uint32_t>(loc)].callsite2Deopt = sizeAndArkDeopt.second; 344 dumper_.deoptNum += deopt.size(); 345 } 346 result.secHead.callsiteNum = callsiteNum; 347 result.secHead.secSize = secSize; 348} 349} // namespace panda::ecmascript::kungfu 350