* 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);
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<uintptr_t, LLVMStackMapType::CallSiteInfo>(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<LLVMStackMapType::LargeInt>(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++) {
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<uint8_t []> stackMapAddr)
{
if (!stackMapAddr) {
LOG_COMPILER(ERROR) << "stackMapAddr nullptr error ! ";
return false;
}
dataInfo_ = std::make_unique<DataInfo>(std::move(stackMapAddr));
llvmStackMap_.head = dataInfo_->Read<struct Header>();
uint32_t numFunctions = dataInfo_->Read<uint32_t>();
uint32_t numConstants = dataInfo_->Read<uint32_t>();
uint32_t numRecords = dataInfo_->Read<uint32_t>();
for (uint32_t i = 0; i < numFunctions; i++) {
auto stkRecord = dataInfo_->Read<struct StkMapSizeRecordTy>();
llvmStackMap_.stkSizeRecords.push_back(stkRecord);
}
for (uint32_t i = 0; i < numConstants; i++) {
auto val = dataInfo_->Read<struct ConstantsTy>();
llvmStackMap_.constants.push_back(val);
}
for (uint32_t i = 0; i < numRecords; i++) {
struct StkMapRecordTy stkSizeRecord;
auto head = dataInfo_->Read<struct StkMapRecordHeadTy>();
stkSizeRecord.head = head;
for (uint16_t j = 0; j < head.numLocations; j++) {
auto location = dataInfo_->Read<struct LocationTy>();
stkSizeRecord.locations.push_back(location);
}
while (dataInfo_->GetOffset() & 7) {
dataInfo_->Read<uint16_t>();
}
uint32_t numLiveOuts = dataInfo_->Read<uint32_t>();
if (numLiveOuts > 0) {
for (uint32_t j = 0; j < numLiveOuts; j++) {
auto liveOut = dataInfo_->Read<struct LiveOutsTy>();
stkSizeRecord.liveOuts.push_back(liveOut);
}
}
while (dataInfo_->GetOffset() & 7) {
dataInfo_->Read<uint16_t>();
}
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<uint8_t> 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<uint8_t> valDerived;
size_t valSizeDerived = 0;
LLVMStackMapType::EncodeRegAndOffset(valDerived, valSizeDerived, stackmapDerived.first,
stackmapDerived.second, triple);
stackmapSize += valDerived.size();
} else {
stackmapNumReduced++;
}
}
return stackmapSize;
}
bool LLVMStackMapParser::CalculateStackMap(std::unique_ptr<uint8_t []> 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;
}
}