/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ecmascript/stackmap/llvm/llvm_stackmap_parser.h" using namespace panda::ecmascript; namespace panda::ecmascript::kungfu { std::string LocationTy::TypeToString(Kind loc) const { switch (loc) { case Kind::REGISTER: return "Register Reg Value in a register"; case Kind::DIRECT: return "Direct Reg + Offset Frame index value"; case Kind::INDIRECT: return "Indirect [Reg + Offset] Spilled value"; case Kind::CONSTANT: return "Constant Offset Small constant"; case Kind::CONSTANTNDEX: return "ConstIndex constants[Offset] Large constant"; default: return "no know location"; } } void LLVMStackMapParser::FilterCallSiteInfo(LLVMStackMapType::CallSiteInfo &info) { ASSERT(GC_PAIR_SIZE == 2); // 2 : The expected value of GC_PAIR_SIZE is 2 ASSERT(info.size() % GC_PAIR_SIZE == 0); for (auto it = info.begin(); it != info.end();) { auto base = it; auto deri = ++it; bool baseIsConst = (base->first == LLVMStackMapType::INVALID_DWARF_REG); bool deriIsConst = (deri->first == LLVMStackMapType::INVALID_DWARF_REG); if (baseIsConst && deriIsConst) { it = info.erase(base, base + GC_PAIR_SIZE); } else if (baseIsConst && !deriIsConst) { base->first = deri->first; base->second = deri->second; it++; } else if (!baseIsConst && deriIsConst) { deri->first = base->first; deri->second = base->second; it++; } else { it++; } } ASSERT(info.size() % GC_PAIR_SIZE == 0); } void LLVMStackMapParser::CalcCallSite() { uint64_t recordNum = 0; LLVMStackMapType::Pc2CallSiteInfo pc2CallSiteInfo; LLVMStackMapType::Pc2Deopt deoptbundles; auto calStkMapRecordFunc = [this, &recordNum, &pc2CallSiteInfo, &deoptbundles](uintptr_t address, uint32_t recordId) { struct StkMapRecordTy &record = llvmStackMap_.stkMapRecord[recordNum + recordId]; struct StkMapRecordHeadTy &recordHead = record.head; uint32_t instructionOffset = recordHead.instructionOffset; uintptr_t pc = address + instructionOffset; uint64_t pID = recordHead.patchPointID; if (pc2CallSiteInfo.find(pc) == pc2CallSiteInfo.end()) { auto p = std::pair(pc, {}); pc2CallSiteInfo.insert(p); } LLVMStackMapType::CallSiteInfo& callSiteInfo = pc2CallSiteInfo.find(pc)->second; ASSERT(recordHead.numLocations > LocationTy::CONSTANT_DEOPT_CNT_INDEX); const int lastDeoptIndex = record.locations[LocationTy::CONSTANT_DEOPT_CNT_INDEX].offsetOrSmallConstant + LocationTy::CONSTANT_DEOPT_CNT_INDEX; for (int j = LocationTy::CONSTANT_FIRST_ELEMENT_INDEX; j < recordHead.numLocations; j++) { const struct LocationTy &loc = record.locations[j]; if (j <= lastDeoptIndex) { switch (loc.location) { case LocationTy::Kind::REGISTER: case LocationTy::Kind::DIRECT: { LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); break; } case LocationTy::Kind::INDIRECT: { OPTIONAL_LOG_COMPILER(DEBUG) << "DwarfRegNum:" << loc.dwarfRegNum << " loc.OffsetOrSmallConstant:" << loc.offsetOrSmallConstant << " address:" << address << " instructionOffset:" << instructionOffset << " callsite:" << " patchPointID :" << std::hex << pID << pc; LLVMStackMapType::DwarfRegAndOffsetType info(loc.dwarfRegNum, loc.offsetOrSmallConstant); deoptbundles[pc].push_back(info); break; } case LocationTy::Kind::CONSTANT: { deoptbundles[pc].push_back(loc.offsetOrSmallConstant); break; } case LocationTy::Kind::CONSTANTNDEX: { auto v = llvmStackMap_.constants[loc.offsetOrSmallConstant].largeConstant; deoptbundles[pc].push_back(static_cast(v)); break; } default: { LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); break; } } } else { switch (loc.location) { case LocationTy::Kind::REGISTER: case LocationTy::Kind::DIRECT: { LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); break; } case LocationTy::Kind::INDIRECT: case LocationTy::Kind::CONSTANT: case LocationTy::Kind::CONSTANTNDEX: { OPTIONAL_LOG_COMPILER(DEBUG) << "DwarfRegNum:" << loc.dwarfRegNum << " loc.OffsetOrSmallConstant:" << loc.offsetOrSmallConstant << " address:" << address << " instructionOffset:" << instructionOffset << " callsite:" << " patchPointID :" << std::hex << pID << pc; uint16_t regNum = (loc.location == LocationTy::Kind::INDIRECT) ? loc.dwarfRegNum : LLVMStackMapType::INVALID_DWARF_REG; int offset = (loc.location == LocationTy::Kind::INDIRECT) ? loc.offsetOrSmallConstant : 0; LLVMStackMapType::DwarfRegAndOffsetType info(regNum, offset); callSiteInfo.emplace_back(info); break; } default: { LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); break; } } } } FilterCallSiteInfo(callSiteInfo); }; const size_t count = llvmStackMap_.stkSizeRecords.size(); for (size_t i = 0; i < count; i++) { // relative offset struct StkMapSizeRecordTy &sizeRec = llvmStackMap_.stkSizeRecords[i]; uintptr_t address = sizeRec.functionAddress; uint64_t recordCount = sizeRec.recordCount; fun2RecordNum_.emplace_back(std::make_pair(address, recordCount)); for (uint64_t k = 0; k < recordCount; k++) { calStkMapRecordFunc(address, k); } recordNum += recordCount; } stackMapInfo.AppendCallSiteInfo(pc2CallSiteInfo); stackMapInfo.AppendDeoptInfo(deoptbundles); } bool LLVMStackMapParser::CalculateStackMap(std::unique_ptr stackMapAddr) { if (!stackMapAddr) { LOG_COMPILER(ERROR) << "stackMapAddr nullptr error ! "; return false; } dataInfo_ = std::make_unique(std::move(stackMapAddr)); llvmStackMap_.head = dataInfo_->Read(); uint32_t numFunctions = dataInfo_->Read(); uint32_t numConstants = dataInfo_->Read(); uint32_t numRecords = dataInfo_->Read(); for (uint32_t i = 0; i < numFunctions; i++) { auto stkRecord = dataInfo_->Read(); llvmStackMap_.stkSizeRecords.push_back(stkRecord); } for (uint32_t i = 0; i < numConstants; i++) { auto val = dataInfo_->Read(); llvmStackMap_.constants.push_back(val); } for (uint32_t i = 0; i < numRecords; i++) { struct StkMapRecordTy stkSizeRecord; auto head = dataInfo_->Read(); stkSizeRecord.head = head; for (uint16_t j = 0; j < head.numLocations; j++) { auto location = dataInfo_->Read(); stkSizeRecord.locations.push_back(location); } while (dataInfo_->GetOffset() & 7) { // 7: 8 byte align dataInfo_->Read(); } uint32_t numLiveOuts = dataInfo_->Read(); if (numLiveOuts > 0) { for (uint32_t j = 0; j < numLiveOuts; j++) { auto liveOut = dataInfo_->Read(); stkSizeRecord.liveOuts.push_back(liveOut); } } while (dataInfo_->GetOffset() & 7) { // 7: 8 byte align dataInfo_->Read(); } llvmStackMap_.stkMapRecord.push_back(stkSizeRecord); } CalcCallSite(); return true; } uint32_t ARKCallsite::CalHeadSize() const { uint32_t headSize = sizeof(head); return headSize; } uint32_t ARKCallsite::CalStackMapSize(Triple triple, size_t &stackmapNumReduced) const { size_t stackmapSize = 0; size_t stackmapsNum = stackmaps.size(); for (size_t i = 0; i < stackmapsNum; i += LLVMStackMapType::STACKMAP_PAIR_SIZE) { std::vector valBase; size_t valSizeBase = 0; auto &stackmapBase = stackmaps.at(i); auto &stackmapDerived = stackmaps.at(i + 1); LLVMStackMapType::EncodeRegAndOffset(valBase, valSizeBase, stackmapBase.first, stackmapBase.second, triple); stackmapSize += valBase.size(); if (stackmapBase.first != stackmapDerived.first || stackmapBase.second != stackmapDerived.second) { std::vector valDerived; size_t valSizeDerived = 0; LLVMStackMapType::EncodeRegAndOffset(valDerived, valSizeDerived, stackmapDerived.first, stackmapDerived.second, triple); stackmapSize += valDerived.size(); } else { // base ref, base ref and derived ref equal ===> remove repeated derived ref reg&offset stackmapNumReduced++; } } return stackmapSize; } bool LLVMStackMapParser::CalculateStackMap(std::unique_ptr stackMapAddr, uintptr_t hostCodeSectionAddr, uintptr_t hostCodeSectionOffset) { bool ret = CalculateStackMap(std::move(stackMapAddr)); if (!ret) { return false; } OPTIONAL_LOG_COMPILER(DEBUG) << "stackmap calculate update funcitonaddress "; for (size_t i = 0; i < llvmStackMap_.stkSizeRecords.size(); i++) { uintptr_t hostAddr = llvmStackMap_.stkSizeRecords[i].functionAddress; uintptr_t offset = hostAddr - hostCodeSectionAddr + hostCodeSectionOffset; llvmStackMap_.stkSizeRecords[i].functionAddress = offset; OPTIONAL_LOG_COMPILER(DEBUG) << std::dec << i << "th function " << std::hex << hostAddr << " ---> " << " offset:" << offset; } stackMapInfo.PopCallSiteInfo(); stackMapInfo.PopDeoptInfo(); fun2RecordNum_.clear(); CalcCallSite(); return true; } } // namespace panda::ecmascript::kungfu