void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, const TValue *p2, TValue *p3, int hasres) { ptrdiff_t result = savestack(L, p3); setobj2s(L, L->top++, f); /* push function (assume EXTRA_STACK) */ setobj2s(L, L->top++, p1); /* 1st argument */ setobj2s(L, L->top++, p2); /* 2nd argument */ if (!hasres) /* no result? 'p3' is third argument */ setobj2s(L, L->top++, p3); /* 3rd argument */ /* metamethod may yield only when called from Lua code */ luaD_call(L, L->top - (4 - hasres), hasres, isLua(L->ci)); if (hasres) { /* if has result, move it to its place */ p3 = restorestack(L, result); setobjs2s(L, p3, --L->top); } }
/* Find error function for runtime errors. Requires an extra stack traversal. */ static ptrdiff_t finderrfunc(lua_State *L) { cTValue *frame = L->base-1, *bot = tvref(L->stack)+LJ_FR2; void *cf = L->cframe; while (frame > bot && cf) { while (cframe_nres(cframe_raw(cf)) < 0) { /* cframe without frame? */ if (frame >= restorestack(L, -cframe_nres(cf))) break; if (cframe_errfunc(cf) >= 0) /* Error handler not inherited (-1)? */ return cframe_errfunc(cf); cf = cframe_prev(cf); /* Else unwind cframe and continue searching. */ if (cf == NULL) return 0; } switch (frame_typep(frame)) { case FRAME_LUA: case FRAME_LUAP: frame = frame_prevl(frame); break; case FRAME_C: cf = cframe_prev(cf); /* fallthrough */ case FRAME_VARG: frame = frame_prevd(frame); break; case FRAME_CONT: if (frame_iscont_fficb(frame)) cf = cframe_prev(cf); frame = frame_prevd(frame); break; case FRAME_CP: if (cframe_canyield(cf)) return 0; if (cframe_errfunc(cf) >= 0) return cframe_errfunc(cf); frame = frame_prevd(frame); break; case FRAME_PCALL: case FRAME_PCALLH: if (frame_func(frame_prevd(frame))->c.ffid == FF_xpcall) return savestack(L, frame_prevd(frame)+1); /* xpcall's errorfunc. */ return 0; default: lua_assert(0); return 0; } } return 0; }
void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1, const TValue *p2, StkId res) { ptrdiff_t result = savestack(L, res); StkId func = L->top; setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ setobj2s(L, func + 1, p1); /* 1st argument */ setobj2s(L, func + 2, p2); /* 2nd argument */ L->top += 3; /* metamethod may yield only when called from Lua code */ if (isLuacode(L->ci)) luaD_call(L, func, 1); else luaD_callnoyield(L, func, 1); res = restorestack(L, result); setobjs2s(L, res, --L->top); /* move result to its place */ }
/* Parse a number literal. */ static void lex_number(LexState *ls, TValue *tv) { StrScanFmt fmt; int c, xp = 'e'; lua_assert(lj_char_isdigit(ls->current)); if ((c = ls->current) == '0') { save_and_next(ls); if ((ls->current | 0x20) == 'x') xp = 'p'; } while (lj_char_isident(ls->current) || ls->current == '.' || ((ls->current == '-' || ls->current == '+') && (c | 0x20) == xp)) { c = ls->current; save_and_next(ls); } save(ls, '\0'); fmt = lj_strscan_scan((const uint8_t *)ls->sb.buf, tv, (LJ_DUALNUM ? STRSCAN_OPT_TOINT : STRSCAN_OPT_TONUM) | (LJ_HASFFI ? (STRSCAN_OPT_LL|STRSCAN_OPT_IMAG) : 0)); if (LJ_DUALNUM && fmt == STRSCAN_INT) { setitype(tv, LJ_TISNUM); } else if (fmt == STRSCAN_NUM) { /* Already in correct format. */ #if LJ_HASFFI } else if (fmt != STRSCAN_ERROR) { lua_State *L = ls->L; GCcdata *cd; lua_assert(fmt == STRSCAN_I64 || fmt == STRSCAN_U64 || fmt == STRSCAN_IMAG); if (!ctype_ctsG(G(L))) { ptrdiff_t oldtop = savestack(L, L->top); luaopen_ffi(L); /* Load FFI library on-demand. */ L->top = restorestack(L, oldtop); } if (fmt == STRSCAN_IMAG) { cd = lj_cdata_new_(L, CTID_COMPLEX_DOUBLE, 2*sizeof(double)); ((double *)cdataptr(cd))[0] = 0; ((double *)cdataptr(cd))[1] = numV(tv); } else { cd = lj_cdata_new_(L, fmt==STRSCAN_I64 ? CTID_INT64 : CTID_UINT64, 8); *(uint64_t *)cdataptr(cd) = tv->u64; } lj_parse_keepcdata(ls, tv, cd); #endif } else { lua_assert(fmt == STRSCAN_ERROR); lj_lex_error(ls, TK_number, LJ_ERR_XNUMBER); } }
/* Runtime error. */ LJ_NOINLINE void lj_err_run(lua_State *L) { ptrdiff_t ef = finderrfunc(L); if (ef) { TValue *errfunc = restorestack(L, ef); TValue *top = L->top; lj_trace_abort(G(L)); if (!tvisfunc(errfunc) || L->status == LUA_ERRERR) { setstrV(L, top-1, lj_err_str(L, LJ_ERR_ERRERR)); lj_err_throw(L, LUA_ERRERR); } L->status = LUA_ERRERR; copyTV(L, top, top-1); copyTV(L, top-1, errfunc); L->top = top+1; lj_vm_call(L, top, 1+1); /* Stack: |errfunc|msg| -> |msg| */ } lj_err_throw(L, LUA_ERRRUN); }
void lj_vmevent_call(lua_State *L, ptrdiff_t argbase, int keeponstack) { global_State *g = G(L); uint8_t oldmask = g->vmevmask; uint8_t oldh = hook_save(g); int status; g->vmevmask = 0; /* Disable all events. */ hook_vmevent(g); status = lj_vm_pcall(L, restorestack(L, argbase), 0+1+keeponstack, 0); if (LJ_UNLIKELY(status)) { /* Really shouldn't use stderr here, but where else to complain? */ L->top--; fprintf(stderr, "VM handler failed: %s\n", tvisstr(L->top) ? strVdata(L->top) : "?"); } hook_restore(g, oldh); if (g->vmevmask != VMEVENT_NOCACHE) g->vmevmask = oldmask; /* Restore event mask, but not if not modified. */ }
/* 调用元操作 * L 虚拟机状态 * f 函数地址 * p1 函数第一个参数 * p2 函数第二个参数 * p3 函数的第三个参数 * hasres 是否存在第三个参数 */ static void callTM (lua_State *L, const TValue *f, const TValue *p1, const TValue *p2, TValue *p3, int hasres) { ptrdiff_t result = savestack(L, p3); /* 保存栈 */ setobj2s(L, L->top++, f); /* push function */ /* 元函数地址 */ setobj2s(L, L->top++, p1); /* 1st argument */ /* 参数1 */ setobj2s(L, L->top++, p2); /* 2nd argument */ /* 参数2 */ /* 如果hasres是1则压入第三个参数 */ if (!hasres) /* no result? 'p3' is third argument */ setobj2s(L, L->top++, p3); /* 3rd argument */ /* metamethod may yield only when called from Lua code */ /* 当从lua代码中调用元方法也许被挂起 */ luaD_call(L, L->top - (4 - hasres), hasres, isLua(L->ci)); /* * 如果有第三个参数 */ if (hasres) { /* if has result, move it to its place */ p3 = restorestack(L, result); setobjs2s(L, p3, --L->top); } }
void luaG_errormsg (lua_State *L) { if (L->errfunc != 0) { /* is there an error handling function? */ StkId errfunc = restorestack(L, L->errfunc); if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top - 1, errfunc); /* push function */ incr_top(L); luaD_call(L, L->top - 2, 1); /* call it */ } else { lua_getfield(L, LUA_GLOBALSINDEX, "_ErrorHandler"); if (!lua_isfunction(L, -1)) { lua_pop(L, 1); } else { lua_pushvalue(L, 1); lua_call(L, 1, 1); lua_pop(L, 1); } } luaD_throw(L, LUA_ERRRUN); }
/* Unwind until stop frame. Optionally cleanup frames. */ static void *err_unwind(lua_State *L, void *stopcf, int errcode) { TValue *frame = L->base-1; void *cf = L->cframe; while (cf) { int32_t nres = cframe_nres(cframe_raw(cf)); if (nres < 0) { /* C frame without Lua frame? */ TValue *top = restorestack(L, -nres); if (frame < top) { /* Frame reached? */ if (errcode) { L->cframe = cframe_prev(cf); L->base = frame+1; unwindstack(L, top); } return cf; } } if (frame <= tvref(L->stack)) break; switch (frame_typep(frame)) { case FRAME_LUA: /* Lua frame. */ case FRAME_LUAP: frame = frame_prevl(frame); break; case FRAME_C: /* C frame. */ #if LJ_UNWIND_EXT if (errcode) { L->cframe = cframe_prev(cf); L->base = frame_prevd(frame) + 1; unwindstack(L, frame); } else if (cf != stopcf) { cf = cframe_prev(cf); frame = frame_prevd(frame); break; } return NULL; /* Continue unwinding. */ #else UNUSED(stopcf); cf = cframe_prev(cf); frame = frame_prevd(frame); break; #endif case FRAME_CP: /* Protected C frame. */ if (cframe_canyield(cf)) { /* Resume? */ if (errcode) { L->cframe = NULL; L->status = (uint8_t)errcode; } return cf; } if (errcode) { L->cframe = cframe_prev(cf); L->base = frame_prevd(frame) + 1; unwindstack(L, frame); } return cf; case FRAME_CONT: /* Continuation frame. */ case FRAME_VARG: /* Vararg frame. */ frame = frame_prevd(frame); break; case FRAME_PCALL: /* FF pcall() frame. */ case FRAME_PCALLH: /* FF pcall() frame inside hook. */ if (errcode) { if (errcode == LUA_YIELD) { frame = frame_prevd(frame); break; } if (frame_typep(frame) == FRAME_PCALL) hook_leave(G(L)); L->cframe = cf; L->base = frame_prevd(frame) + 1; unwindstack(L, L->base); } return (void *)((intptr_t)cf | CFRAME_UNWIND_FF); } } /* No C frame. */ if (errcode) { L->cframe = NULL; L->base = tvref(L->stack)+1; unwindstack(L, L->base); if (G(L)->panic) G(L)->panic(L); exit(EXIT_FAILURE); } return L; /* Anything non-NULL will do. */ }
void luaV_execute (lua_State *L, int nexeccalls) { LClosure *cl; StkId base; TValue *k; const Instruction *pc; reentry: /* entry point */ lua_assert(isLua(L->ci)); pc = L->savedpc; cl = &clvalue(L->ci->func)->l; base = L->base; k = cl->p->k; /* main loop of interpreter */ for (;;) { const Instruction i = *pc++; StkId ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { traceexec(L, pc); if (L->status == LUA_YIELD) { /* did hook yield? */ L->savedpc = pc - 1; return; } base = L->base; } /* warning!! several calls may realloc the stack and invalidate `ra' */ ra = RA(i); lua_assert(base == L->base && L->base == L->ci->base); lua_assert(base <= L->top && L->top <= L->stack + L->stacksize); lua_assert(L->top == L->ci->top || luaG_checkopenop(i)); switch (GET_OPCODE(i)) { case OP_MOVE: { setobjs2s(L, ra, RB(i)); continue; } case OP_LOADK: { setobj2s(L, ra, KBx(i)); continue; } case OP_LOADBOOL: { setbvalue(ra, GETARG_B(i)); if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ continue; } case OP_LOADNIL: { TValue *rb = RB(i); do { setnilvalue(rb--); } while (rb >= ra); continue; } case OP_GETUPVAL: { int b = GETARG_B(i); setobj2s(L, ra, cl->upvals[b]->v); continue; } case OP_GETGLOBAL: { TValue g; TValue *rb = KBx(i); sethvalue(L, &g, cl->env); lua_assert(ttisstring(rb)); Protect(luaV_gettable(L, &g, rb, ra)); continue; } case OP_GETTABLE: { Protect(luaV_gettable(L, RB(i), RKC(i), ra)); continue; } case OP_SETGLOBAL: { TValue g; sethvalue(L, &g, cl->env); lua_assert(ttisstring(KBx(i))); Protect(luaV_settable(L, &g, KBx(i), ra)); continue; } case OP_SETUPVAL: { UpVal *uv = cl->upvals[GETARG_B(i)]; setobj(L, uv->v, ra); luaC_barrier(L, uv, ra); continue; } case OP_SETTABLE: { Protect(luaV_settable(L, ra, RKB(i), RKC(i))); continue; } case OP_NEWTABLE: { int b = GETARG_B(i); int c = GETARG_C(i); Table *h; Protect(h = luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); sethvalue(L, RA(i), h); Protect(luaC_checkGC(L)); continue; } case OP_SELF: { StkId rb = RB(i); setobjs2s(L, ra+1, rb); Protect(luaV_gettable(L, rb, RKC(i), ra)); continue; } case OP_ADD: { arith_op(luai_numadd, TM_ADD); continue; } case OP_SUB: { arith_op(luai_numsub, TM_SUB); continue; } case OP_MUL: { arith_op(luai_nummul, TM_MUL); continue; } case OP_DIV: { arith_op(luai_lnumdiv, TM_DIV); continue; } case OP_MOD: { arith_op(luai_lnummod, TM_MOD); continue; } case OP_POW: { arith_op(luai_numpow, TM_POW); continue; } case OP_UNM: { TValue *rb = RB(i); if (ttisnumber(rb)) { lua_Number nb = nvalue(rb); setnvalue(ra, luai_numunm(nb)); } else { Protect(Arith(L, ra, rb, rb, TM_UNM)); } continue; } case OP_NOT: { int res = l_isfalse(RB(i)); /* next assignment may change this value */ setbvalue(ra, res); continue; } case OP_LEN: { const TValue *rb = RB(i); switch (ttype(rb)) { case LUA_TTABLE: case LUA_TROTABLE: { setnvalue(ra, ttistable(rb) ? cast_num(luaH_getn(hvalue(rb))) : cast_num(luaH_getn_ro(rvalue(rb)))); break; } case LUA_TSTRING: { setnvalue(ra, cast_num(tsvalue(rb)->len)); break; } default: { /* try metamethod */ ptrdiff_t br = savestack(L, rb); Protect( if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN)) luaG_typeerror(L, restorestack(L, br), "get length of"); ) } } continue; } case OP_CONCAT: { int b = GETARG_B(i); int c = GETARG_C(i); Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); setobjs2s(L, RA(i), base+b); continue; } case OP_JMP: { dojump(L, pc, GETARG_sBx(i)); continue; } case OP_EQ: { TValue *rb = RKB(i); TValue *rc = RKC(i); Protect( if (equalobj(L, rb, rc) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); ) pc++; continue; } case OP_LT: { Protect( if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); ) pc++; continue; } case OP_LE: { Protect( if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); ) pc++; continue; }
/* 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 = map + nent + snap->depth; int32_t ftsz0; BCReg nslots = snap->nslots; 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 + nslots > tvref(L->maxstack))) { L->top = curr_topL(L); lj_state_growstack(L, nslots - 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]; IRRef ref = snap_ref(sn); BCReg s = snap_slot(sn); TValue *o = &frame[s]; /* Stack slots are relative to start frame. */ IRIns *ir = &T->ir[ref]; if (irref_isk(ref)) { /* Restore constant slot. */ lj_ir_kvalue(L, o, ir); if ((sn & (SNAP_CONT|SNAP_FRAME))) { /* Overwrite tag with frame link. */ o->fr.tp.ftsz = s != 0 ? (int32_t)*flinks-- : ftsz0; if ((sn & SNAP_FRAME)) { GCfunc *fn = ir_kfunc(ir); if (isluafunc(fn)) { MSize framesize = funcproto(fn)->framesize; L->base = ++o; if (LJ_UNLIKELY(o + framesize > tvref(L->maxstack))) { ptrdiff_t fsave = savestack(L, frame); L->top = o; lj_state_growstack(L, framesize); /* Grow again. */ frame = restorestack(L, fsave); } } } } } else if (!(sn & SNAP_NORESTORE)) { IRType1 t = ir->t; RegSP rs = ir->prev; lua_assert(!(sn & (SNAP_CONT|SNAP_FRAME))); if (LJ_UNLIKELY(bloomtest(rfilt, ref))) rs = snap_renameref(T, snapno, ref, rs); if (ra_hasspill(regsp_spill(rs))) { /* Restore from spill slot. */ int32_t *sps = &ex->spill[regsp_spill(rs)]; if (LJ_SOFTFP && (sn & SNAP_SOFTFPNUM)) { o->u32.lo = (uint32_t)*sps; } else if (irt_isinteger(t)) { setintV(o, *sps); #if !LJ_SOFTFP } else if (irt_isnum(t)) { o->u64 = *(uint64_t *)sps; #endif #if LJ_64 } else if (irt_islightud(t)) { /* 64 bit lightuserdata which may escape already has the tag bits. */ o->u64 = *(uint64_t *)sps; #endif } else { lua_assert(!irt_ispri(t)); /* PRI refs never have a spill slot. */ setgcrefi(o->gcr, *sps); setitype(o, irt_toitype(t)); } } else { /* Restore from register. */ Reg r = regsp_reg(rs); lua_assert(ra_hasreg(r)); if (LJ_SOFTFP && (sn & SNAP_SOFTFPNUM)) { o->u32.lo = (uint32_t)ex->gpr[r-RID_MIN_GPR]; } else if (irt_isinteger(t)) { setintV(o, (int32_t)ex->gpr[r-RID_MIN_GPR]); #if !LJ_SOFTFP } else if (irt_isnum(t)) { setnumV(o, ex->fpr[r-RID_MIN_FPR]); #endif #if LJ_64 } else if (irt_islightud(t)) { /* 64 bit lightuserdata which may escape already has the tag bits. */ o->u64 = ex->gpr[r-RID_MIN_GPR]; #endif } else { if (!irt_ispri(t)) setgcrefi(o->gcr, ex->gpr[r-RID_MIN_GPR]); setitype(o, irt_toitype(t)); } } if (LJ_SOFTFP && (sn & SNAP_SOFTFPNUM)) { rs = (ir+1)->prev; if (LJ_UNLIKELY(bloomtest(rfilt, ref+1))) rs = snap_renameref(T, snapno, ref+1, rs); o->u32.hi = (ra_hasspill(regsp_spill(rs))) ? (uint32_t)*&ex->spill[regsp_spill(rs)] : (uint32_t)ex->gpr[regsp_reg(rs)-RID_MIN_GPR]; } } } switch (bc_op(*pc)) { case BC_CALLM: case BC_CALLMT: case BC_RETM: case BC_TSETM: L->top = frame + nslots; break; default: L->top = curr_topL(L); break; } lua_assert(map + nent == flinks); return pc; }
/* Load FFI library on-demand. Needed if we create cdata objects. */ static void lex_loadffi(lua_State *L) { ptrdiff_t oldtop = savestack(L, L->top); luaopen_ffi(L); L->top = restorestack(L, oldtop); }