void FixupMap::fixupWorkSimulated(ExecutionContext* ec) const { TRACE(1, "fixup(begin):\n"); auto isVMFrame = [] (ActRec* ar, const vixl::Simulator* sim) { // If this assert is failing, you may have forgotten a sync point somewhere assert(ar); bool ret = uintptr_t(ar) - s_stackLimit >= s_stackSize && !sim->is_on_stack(ar); assert(!ret || (ar >= vmStack().getStackLowAddress() && ar < vmStack().getStackHighAddress()) || ar->resumed()); return ret; }; // For each nested simulator (corresponding to nested VM invocations), look at // its PC to find a potential fixup key. // // Callstack walking is necessary, because we may get called from a // uniqueStub. for (int i = ec->m_activeSims.size() - 1; i >= 0; --i) { auto const* sim = ec->m_activeSims[i]; auto* rbp = reinterpret_cast<ActRec*>(sim->xreg(JIT::ARM::rVmFp.code())); auto tca = reinterpret_cast<TCA>(sim->pc()); TRACE(2, "considering frame %p, %p\n", rbp, tca); while (rbp && !isVMFrame(rbp, sim)) { tca = reinterpret_cast<TCA>(rbp->m_savedRip); rbp = rbp->m_sfp; } if (!rbp) continue; auto* ent = m_fixups.find(tca); if (!ent) { continue; } if (ent->isIndirect()) { not_implemented(); } VMRegs regs; regsFromActRec(tca, rbp, ent->fixup, ®s); TRACE(2, "fixup(end): func %s fp %p sp %p pc %p\b", regs.m_fp->m_func->name()->data(), regs.m_fp, regs.m_sp, regs.m_pc); vmfp() = const_cast<ActRec*>(regs.m_fp); vmpc() = reinterpret_cast<PC>(regs.m_pc); vmsp() = regs.m_sp; return; } // This shouldn't be reached. always_assert(false); }
bool FixupMap::getFrameRegs(const ActRec* ar, const ActRec* prevAr, VMRegs* outVMRegs) const { CTCA tca = (CTCA)ar->m_savedRip; // Non-obvious off-by-one fun: if the *return address* points into the TC, // then the frame we were running on in the TC is actually the previous // frame. ar = ar->m_sfp; auto* ent = m_fixups.find(tca); if (!ent) return false; if (ent->isIndirect()) { // Note: if indirect fixups happen frequently enough, we could // just compare savedRip to be less than some threshold where // stubs in a.code stop. assertx(prevAr); auto pRealRip = ent->indirect.returnIpDisp + uintptr_t(prevAr->m_sfp); ent = m_fixups.find(*reinterpret_cast<CTCA*>(pRealRip)); assertx(ent && !ent->isIndirect()); } regsFromActRec(tca, ar, ent->fixup, outVMRegs); return true; }