diff --git a/lcode.c b/lcode.c index 97aa9dda..8f9fa408 100644 --- a/lcode.c +++ b/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.137 2017/11/28 12:58:18 roberto Exp roberto $ +** $Id: lcode.c,v 2.138 2017/11/28 15:26:15 roberto Exp roberto $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -152,7 +152,17 @@ int luaK_jump (FuncState *fs) { ** Code a 'return' instruction */ void luaK_ret (FuncState *fs, int first, int nret) { - luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); + switch (nret) { + case 0: + luaK_codeABC(fs, OP_RETURN0, 0, 0, 0); + break; + case 1: + luaK_codeABC(fs, OP_RETURN1, first, 0, 0); + break; + default: + luaK_codeABC(fs, OP_RETURN, first, nret + 1, 0); + break; + } } diff --git a/lopcodes.c b/lopcodes.c index 122157eb..1b081639 100644 --- a/lopcodes.c +++ b/lopcodes.c @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.c,v 1.69 2017/11/22 18:41:20 roberto Exp roberto $ +** $Id: lopcodes.c,v 1.70 2017/11/27 17:44:31 roberto Exp roberto $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -75,6 +75,8 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { "CALL", "TAILCALL", "RETURN", + "RETURN0", + "RETURN1", "FORLOOP", "FORPREP", "TFORCALL", @@ -146,6 +148,8 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { ,opmode(0, 1, iABC) /* OP_CALL */ ,opmode(0, 1, iABC) /* OP_TAILCALL */ ,opmode(0, 0, iABC) /* OP_RETURN */ + ,opmode(0, 0, iABC) /* OP_RETURN0 */ + ,opmode(0, 0, iABC) /* OP_RETURN1 */ ,opmode(0, 1, iABx) /* OP_FORLOOP */ ,opmode(0, 1, iABx) /* OP_FORPREP */ ,opmode(0, 0, iABC) /* OP_TFORCALL */ diff --git a/lopcodes.h b/lopcodes.h index f2b67165..433d97a2 100644 --- a/lopcodes.h +++ b/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.171 2017/11/27 17:44:31 roberto Exp roberto $ +** $Id: lopcodes.h,v 1.172 2017/11/28 12:58:18 roberto Exp roberto $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -252,7 +252,10 @@ OP_TESTSET,/* A B if (not R(B) == k) then R(A) := R(B) else pc++ */ OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ + OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ +OP_RETURN0,/* return */ +OP_RETURN1,/* A return R(A) */ OP_FORLOOP,/* A Bx R(A)+=R(A+2); if R(A) top = (c), /* limit of live values */ \ @@ -824,11 +829,16 @@ void luaV_finishOp (lua_State *L) { void luaV_execute (lua_State *L, CallInfo *ci) { - LClosure *cl = clLvalue(s2v(ci->func)); - TValue *k = cl->p->k; - StkId base = ci->func + 1; + LClosure *cl; + TValue *k; + StkId base; + const Instruction *pc; int trap = ci->u.l.trap; - const Instruction *pc = ci->u.l.savedpc; + tailcall: + cl = clLvalue(s2v(ci->func)); + k = cl->p->k; + base = ci->func + 1; + pc = ci->u.l.savedpc; /* main loop of interpreter */ for (;;) { int cond; /* flag for conditional jumps */ @@ -1438,16 +1448,15 @@ void luaV_execute (lua_State *L, CallInfo *ci) { vra = s2v(ra); b++; /* there is now one extra argument */ } - if (!ttisLclosure(vra)) /* C function? */ + if (!ttisLclosure(vra)) { /* C function? */ Protect(luaD_call(L, ra, LUA_MULTRET)); /* call it */ + /* next instruction will do the return */ + } else { /* tail call */ if (cl->p->sizep > 0) /* close upvalues from previous call */ luaF_close(L, ci->func + 1); luaD_pretailcall(L, ci, ra, b); /* prepare call frame */ - cl = clLvalue(s2v(ci->func)); - k = cl->p->k; - updatebase(ci); - pc = ci->u.l.savedpc; + goto tailcall; } vmbreak; } @@ -1455,9 +1464,43 @@ void luaV_execute (lua_State *L, CallInfo *ci) { int b = GETARG_B(i); if (cl->p->sizep > 0) luaF_close(L, base); - savepc(L); - luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra))); - return; /* external invocation: return */ + halfProtect( + luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra))) + ); + return; + } + vmcase(OP_RETURN0) { + if (cl->p->sizep > 0) + luaF_close(L, base); + if (L->hookmask) + halfProtect(luaD_poscall(L, ci, ra, 0)); /* no hurry... */ + else { + int nres = ci->nresults; + L->ci = ci->previous; /* back to caller */ + L->top = base - 1; + while (nres-- > 0) + setnilvalue(s2v(L->top++)); /* all results are nil */ + } + return; + } + vmcase(OP_RETURN1) { + if (cl->p->sizep > 0) + luaF_close(L, base); + if (L->hookmask) + halfProtect(luaD_poscall(L, ci, ra, 1)); /* no hurry... */ + else { + int nres = ci->nresults; + L->ci = ci->previous; /* back to caller */ + if (nres == 0) + L->top = base - 1; /* asked for no results */ + else { + setobjs2s(L, base - 1, ra); /* at least this result */ + L->top = base; + while (--nres > 0) /* complete missing results */ + setnilvalue(s2v(L->top++)); + } + } + return; } vmcase(OP_FORLOOP) { if (ttisinteger(vra)) { /* integer loop? */