void SrcRec::chainFrom(IncomingBranch br) { assert(br.type() == IncomingBranch::Tag::ADDR || mcg->code.isValidCodeAddress(br.toSmash())); TCA destAddr = getTopTranslation(); m_incomingBranches.push_back(br); TRACE(1, "SrcRec(%p)::chainFrom %p -> %p (type %d); %zd incoming branches\n", this, br.toSmash(), destAddr, br.type(), m_incomingBranches.size()); br.patch(destAddr); }
void SrcRec::chainFrom(IncomingBranch br) { assertx(br.type() == IncomingBranch::Tag::ADDR || tc::isValidCodeAddress(br.toSmash())); TCA destAddr = getTopTranslation(); m_incomingBranches.push_back(br); TRACE(1, "SrcRec(%p)::chainFrom %p -> %p (type %d); %zd incoming branches\n", this, br.toSmash(), destAddr, static_cast<int>(br.type()), m_incomingBranches.size()); br.patch(destAddr); if (RuntimeOption::EvalEnableReusableTC) { tc::recordJump(br.toSmash(), this); } }
TCA bindAddr(TCA toSmash, SrcKey destSk, TransFlags trflags, bool& smashed) { auto const sr = srcDB().find(destSk); always_assert(sr); auto const tDest = sr->getTopTranslation(); if (tDest == nullptr) return nullptr; auto codeLock = lockCode(); auto addr = reinterpret_cast<TCA*>(toSmash); if (*addr == tDest) { // Already smashed return tDest; } sr->chainFrom(IncomingBranch::addr(addr)); smashed = true; return tDest; }
TCA bindJmp(TCA toSmash, SrcKey destSk, TransFlags trflags, bool& smashed) { auto const sr = srcDB().find(destSk); always_assert(sr); auto const tDest = sr->getTopTranslation(); if (tDest == nullptr) return nullptr; auto codeLock = lockCode(); auto const isJcc = [&] { switch (arch()) { case Arch::X64: { x64::DecodedInstruction di(toSmash); return (di.isBranch() && !di.isJmp()); } case Arch::ARM: { auto instr = reinterpret_cast<vixl::Instruction*>(toSmash); return instr->IsCondBranchImm(); } case Arch::PPC64: ppc64_asm::DecodedInstruction di(toSmash); return (di.isBranch() && !di.isJmp()); } not_reached(); }(); if (isJcc) { auto const target = smashableJccTarget(toSmash); assertx(target); // Return if already smashed. if (target == tDest) return tDest; sr->chainFrom(IncomingBranch::jccFrom(toSmash)); } else { auto const target = smashableJmpTarget(toSmash); assertx(target); // Return if already smashed. if (!target || target == tDest) return tDest; sr->chainFrom(IncomingBranch::jmpFrom(toSmash)); } smashed = true; return tDest; }