void SrcRec::emitFallbackJump(CodeBlock& cb, ConditionCode cc /* = -1 */) { // This is a spurious platform dependency. TODO(2990497) JIT::prepareForSmash( cb, cc == CC_None ? JIT::X64::kJmpLen : JIT::X64::kJmpccLen ); auto from = cb.frontier(); TCA destAddr = getFallbackTranslation(); auto incoming = cc < 0 ? IncomingBranch::jmpFrom(from) : IncomingBranch::jccFrom(from); JIT::emitSmashableJump(cb, destAddr, cc); // We'll need to know the location of this jump later so we can // patch it to new translations added to the chain. m_inProgressTailJumps.push_back(incoming); }
void SrcRec::emitFallbackJump(TCA from, int cc /* = -1 */) { TCA destAddr = getFallbackTranslation(); auto incoming = cc < 0 ? IncomingBranch::jmpFrom(from) : IncomingBranch::jccFrom(from); auto& a = tx64->getAsmFor(from); // emit dummy jump to be smashed via patch() if (cc < 0) { a.jmp(a.frontier()); } else { assert(incoming.type() == IncomingBranch::Tag::JCC); a.jcc((ConditionCode)cc, a.frontier()); } patch(incoming, destAddr); // We'll need to know the location of this jump later so we can // patch it to new translations added to the chain. m_inProgressTailJumps.push_back(incoming); }
FPInvOffset SrcRec::nonResumedSPOff() const { return svcreq::extract_spoff(getFallbackTranslation()); }
void emit_svcreq_stub(Venv& env, const Venv::SvcReqPatch& p) { auto& frozen = env.text.frozen().code; TCA stub = nullptr; switch (p.svcreq.op) { case Vinstr::bindjmp: { auto const& i = p.svcreq.bindjmp_; assertx(p.jmp && !p.jcc); stub = svcreq::emit_bindjmp_stub(frozen, env.text.data(), env.meta, i.spOff, p.jmp, i.target, i.trflags); } break; case Vinstr::bindjcc: { auto const& i = p.svcreq.bindjcc_; assertx(!p.jmp && p.jcc); stub = svcreq::emit_bindjmp_stub(frozen, env.text.data(), env.meta, i.spOff, p.jcc, i.target, i.trflags); } break; case Vinstr::bindaddr: { auto const& i = p.svcreq.bindaddr_; assertx(!p.jmp && !p.jcc); stub = svcreq::emit_bindaddr_stub(frozen, env.text.data(), env.meta, i.spOff, i.addr.get(), i.target, TransFlags{}); // The bound pointer may not belong to the data segment, as is the case // with SSwitchMap (see #10347945) auto realAddr = env.text.data().contains((TCA)i.addr.get()) ? (TCA*)env.text.data().toDestAddress((TCA)i.addr.get()) : (TCA*)i.addr.get(); *realAddr = stub; } break; case Vinstr::fallback: { auto const& i = p.svcreq.fallback_; assertx(p.jmp && !p.jcc); auto const srcrec = tc::findSrcRec(i.target); always_assert(srcrec); stub = i.trflags.packed ? svcreq::emit_retranslate_stub(frozen, env.text.data(), i.spOff, i.target, i.trflags) : srcrec->getFallbackTranslation(); } break; case Vinstr::fallbackcc: { auto const& i = p.svcreq.fallbackcc_; assertx(!p.jmp && p.jcc); auto const srcrec = tc::findSrcRec(i.target); always_assert(srcrec); stub = i.trflags.packed ? svcreq::emit_retranslate_stub(frozen, env.text.data(), i.spOff, i.target, i.trflags) : srcrec->getFallbackTranslation(); } break; default: always_assert(false); } assertx(stub != nullptr); // Register any necessary patches by creating fake labels for the stubs. if (p.jmp) { env.jmps.push_back({p.jmp, Vlabel { env.addrs.size() }}); env.addrs.push_back(stub); } if (p.jcc) { env.jccs.push_back({p.jcc, Vlabel { env.addrs.size() }}); env.addrs.push_back(stub); } }
void emit_svcreq_stub(Venv& env, const Venv::SvcReqPatch& p) { auto& frozen = env.text.frozen().code; TCA stub = nullptr; switch (p.svcreq.op) { case Vinstr::bindjmp: { auto const& i = p.svcreq.bindjmp_; assertx(p.jmp && !p.jcc); stub = svcreq::emit_bindjmp_stub(frozen, env.meta, i.spOff, p.jmp, i.target, i.trflags); } break; case Vinstr::bindjcc: { auto const& i = p.svcreq.bindjcc_; assertx(!p.jmp && p.jcc); stub = svcreq::emit_bindjmp_stub(frozen, env.meta, i.spOff, p.jcc, i.target, i.trflags); } break; case Vinstr::bindaddr: { auto const& i = p.svcreq.bindaddr_; assertx(!p.jmp && !p.jcc); stub = svcreq::emit_bindaddr_stub(frozen, env.meta, i.spOff, i.addr, i.target, TransFlags{}); *i.addr = stub; } break; case Vinstr::bindjcc1st: { auto const& i = p.svcreq.bindjcc1st_; assertx(p.jmp && p.jcc); stub = svcreq::emit_bindjcc1st_stub(frozen, env.meta, i.spOff, p.jcc, i.targets[1], i.targets[0], i.cc); } break; case Vinstr::fallback: { auto const& i = p.svcreq.fallback_; assertx(p.jmp && !p.jcc); auto const srcrec = mcg->tx().getSrcRec(i.target); stub = i.trflags.packed ? svcreq::emit_retranslate_stub(frozen, i.spOff, i.target, i.trflags) : srcrec->getFallbackTranslation(); } break; case Vinstr::fallbackcc: { auto const& i = p.svcreq.fallbackcc_; assertx(!p.jmp && p.jcc); auto const srcrec = mcg->tx().getSrcRec(i.target); stub = i.trflags.packed ? svcreq::emit_retranslate_stub(frozen, i.spOff, i.target, i.trflags) : srcrec->getFallbackTranslation(); } break; default: always_assert(false); } assertx(stub != nullptr); // Register any necessary patches by creating fake labels for the stubs. if (p.jmp) { env.jmps.push_back({p.jmp, Vlabel { env.addrs.size() }}); env.addrs.push_back(stub); } if (p.jcc) { env.jccs.push_back({p.jcc, Vlabel { env.addrs.size() }}); env.addrs.push_back(stub); } }