void fixupWork(ExecutionContext* ec, ActRec* nextRbp) { assertx(RuntimeOption::EvalJit); TRACE(1, "fixup(begin):\n"); while (true) { auto const rbp = nextRbp; nextRbp = rbp->m_sfp; assertx(nextRbp && nextRbp != rbp && "Missing fixup for native call"); TRACE(2, "considering frame %p, %p\n", rbp, (void*)rbp->m_savedRip); if (isVMFrame(nextRbp)) { TRACE(2, "fixup checking vm frame %s\n", nextRbp->m_func->name()->data()); VMRegs regs; if (getFrameRegs(rbp, ®s)) { TRACE(2, "fixup(end): func %s fp %p sp %p pc %p\n", regs.fp->m_func->name()->data(), regs.fp, regs.sp, regs.pc); auto& vmRegs = vmRegsUnsafe(); vmRegs.fp = const_cast<ActRec*>(regs.fp); vmRegs.pc = reinterpret_cast<PC>(regs.pc); vmRegs.stack.top() = regs.sp; return; } } } }
ActRec* callerFrameHelper() { DECLARE_FRAME_POINTER(frame); auto rbp = frame->m_sfp; while (true) { assertx(rbp && rbp != rbp->m_sfp && "Missing fixup for native call"); if (isVMFrame(rbp)) { return rbp; } rbp = rbp->m_sfp; } }
void FixupMap::fixupWork(ExecutionContext* ec, ActRec* rbp) const { assert(RuntimeOption::EvalJit); TRACE(1, "fixup(begin):\n"); auto* nextRbp = rbp; rbp = 0; do { auto* prevRbp = rbp; rbp = nextRbp; assert(rbp && "Missing fixup for native call"); nextRbp = rbp->m_sfp; TRACE(2, "considering frame %p, %p\n", rbp, (void*)rbp->m_savedRip); if (isVMFrame(ec, nextRbp)) { TRACE(2, "fixup checking vm frame %s\n", nextRbp->m_func->name()->data()); VMRegs regs; if (getFrameRegs(rbp, prevRbp, ®s)) { TRACE(2, "fixup(end): func %s fp %p sp %p pc %p\n", regs.m_fp->m_func->name()->data(), regs.m_fp, regs.m_sp, regs.m_pc); auto& vmRegs = vmRegsUnsafe(); vmRegs.fp = const_cast<ActRec*>(regs.m_fp); vmRegs.pc = reinterpret_cast<PC>(regs.m_pc); vmRegs.stack.top() = regs.m_sp; return; } } } while (rbp && rbp != nextRbp); // OK, we've exhausted the entire actRec chain. We are only // invoking ::fixup() from contexts that were known to be called out // of the TC, so this cannot happen. always_assert(false); }