/* Tailcall from C function. */ int lj_meta_tailcall(lua_State *L, cTValue *tv) { TValue *base = L->base; TValue *top = L->top; const BCIns *pc = frame_pc(base-1); /* Preserve old PC from frame. */ copyTV(L, base-1-LJ_FR2, tv); /* Replace frame with new object. */ if (LJ_FR2) (top++)->u64 = LJ_CONT_TAILCALL; else top->u32.lo = LJ_CONT_TAILCALL; setframe_pc(top++, pc); if (LJ_FR2) top++; setframe_gc(top, obj2gco(L), LJ_TTHREAD); /* Dummy frame object. */ setframe_ftsz(top, ((char *)(top+1) - (char *)base) + FRAME_CONT); L->base = L->top = top+1; /* ** before: [old_mo|PC] [... ...] ** ^base ^top ** after: [new_mo|itype] [... ...] [NULL|PC] [dummy|delta] ** ^base/top ** tailcall: [new_mo|PC] [... ...] ** ^base ^top */ return 0; }
/* Tailcall from C function. */ int lj_meta_tailcall(lua_State *L, cTValue *tv) { TValue *base = L->base; TValue *top = L->top; const BCIns *pc = frame_pc(base-1); /* Preserve old PC from frame. */ copyTV(L, base-1, tv); /* Replace frame with new object. */ top->u64 = 0; setframe_pc(top, pc); setframe_gc(top+1, obj2gco(L)); /* Dummy frame object. */ setframe_ftsz(top+1, (int)((char *)(top+2) - (char *)base) + FRAME_CONT); L->base = L->top = top+2; /* ** before: [old_mo|PC] [... ...] ** ^base ^top ** after: [new_mo|itype] [... ...] [NULL|PC] [dummy|delta] ** ^base/top ** tailcall: [new_mo|PC] [... ...] ** ^base ^top */ return 0; }
/* Restore interpreter state from exit state with the help of a snapshot. */ const BCIns *lj_snap_restore(jit_State *J, void *exptr) { ExitState *ex = (ExitState *)exptr; SnapNo snapno = J->exitno; /* For now, snapno == exitno. */ GCtrace *T = traceref(J, J->parent); SnapShot *snap = &T->snap[snapno]; MSize n, nent = snap->nent; SnapEntry *map = &T->snapmap[snap->mapofs]; SnapEntry *flinks = &T->snapmap[snap_nextofs(T, snap)-1]; ptrdiff_t ftsz0; TValue *frame; BloomFilter rfilt = snap_renamefilter(T, snapno); const BCIns *pc = snap_pc(map[nent]); lua_State *L = J->L; /* Set interpreter PC to the next PC to get correct error messages. */ setcframe_pc(cframe_raw(L->cframe), pc+1); /* Make sure the stack is big enough for the slots from the snapshot. */ if (LJ_UNLIKELY(L->base + snap->topslot >= tvref(L->maxstack))) { L->top = curr_topL(L); lj_state_growstack(L, snap->topslot - curr_proto(L)->framesize); } /* Fill stack slots with data from the registers and spill slots. */ frame = L->base-1; ftsz0 = frame_ftsz(frame); /* Preserve link to previous frame in slot #0. */ for (n = 0; n < nent; n++) { SnapEntry sn = map[n]; if (!(sn & SNAP_NORESTORE)) { TValue *o = &frame[snap_slot(sn)]; IRRef ref = snap_ref(sn); IRIns *ir = &T->ir[ref]; if (ir->r == RID_SUNK) { MSize j; for (j = 0; j < n; j++) if (snap_ref(map[j]) == ref) { /* De-duplicate sunk allocations. */ copyTV(L, o, &frame[snap_slot(map[j])]); goto dupslot; } snap_unsink(J, T, ex, snapno, rfilt, ir, o); dupslot: continue; } snap_restoreval(J, T, ex, snapno, rfilt, ref, o); if (LJ_SOFTFP && (sn & SNAP_SOFTFPNUM) && tvisint(o)) { TValue tmp; snap_restoreval(J, T, ex, snapno, rfilt, ref+1, &tmp); o->u32.hi = tmp.u32.lo; } else if ((sn & (SNAP_CONT|SNAP_FRAME))) { lua_assert(!LJ_FR2); /* TODO_FR2: store 64 bit PCs. */ /* Overwrite tag with frame link. */ setframe_ftsz(o, snap_slot(sn) != 0 ? (int32_t)*flinks-- : ftsz0); L->base = o+1; } } } lua_assert(map + nent == flinks); /* Compute current stack top. */ switch (bc_op(*pc)) { default: if (bc_op(*pc) < BC_FUNCF) { L->top = curr_topL(L); break; } /* fallthrough */ case BC_CALLM: case BC_CALLMT: case BC_RETM: case BC_TSETM: L->top = frame + snap->nslots; break; } return pc; }