Browse Source

some simplifications/optimizations in returns from Lua functions

Roberto Ierusalimschy 7 years ago
parent
commit
0682fe8169
7 changed files with 80 additions and 77 deletions
  1. 18 14
      lcode.c
  2. 16 8
      ldo.c
  3. 1 4
      ldo.h
  4. 1 3
      lopcodes.c
  5. 12 10
      lopcodes.h
  6. 6 4
      ltm.c
  7. 26 34
      lvm.c

+ 18 - 14
lcode.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.c,v 2.152 2018/01/28 15:13:26 roberto Exp roberto $
+** $Id: lcode.c,v 2.153 2018/02/09 15:16:06 roberto Exp roberto $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -158,16 +158,12 @@ int luaK_jump (FuncState *fs) {
 */
 void luaK_ret (FuncState *fs, int first, int nret) {
   OpCode op;
-  if (fs->f->is_vararg)
-    op = OP_RETVARARG;
-  else {
-    switch (nret) {
-      case 0: op = OP_RETURN0; break;
-      case 1: op = OP_RETURN1; break;
-      default: op = OP_RETURN; break;
-    }
+  switch (nret) {
+    case 0: op = OP_RETURN0; break;
+    case 1: op = OP_RETURN1; break;
+    default: op = OP_RETURN; break;
   }
-  luaK_codeABC(fs, op, first, nret + 1, fs->f->numparams);
+  luaK_codeABC(fs, op, first, nret + 1, 0);
 }
 
 
@@ -1646,10 +1642,18 @@ void luaK_finish (FuncState *fs) {
     Instruction *pc = &p->code[i];
     lua_assert(i == 0 || isOT(*(pc - 1)) == isIT(*pc));
     switch (GET_OPCODE(*pc)) {
-      case OP_RETURN: case OP_RETURN0: case OP_RETURN1:
-      case OP_RETVARARG: case OP_TAILCALL: {
-        if (p->sizep > 0)
-          SETARG_k(*pc, 1);  /* signal that they must close upvalues */
+      case OP_RETURN0: case OP_RETURN1: {
+        if (p->sizep == 0 && !p->is_vararg)
+          break;  /* no extra work */
+        /* else use OP_RETURN to do the extra work */
+        SET_OPCODE(*pc, OP_RETURN);
+        /* FALLTHROUGH */
+      }
+      case OP_RETURN: case OP_TAILCALL: {
+        if (p->sizep > 0 || p->is_vararg) {
+          SETARG_C(*pc, p->is_vararg ? p->numparams + 1 : 0);
+          SETARG_k(*pc, 1);  /* signal that there is extra work */
+        }
         break;
       }
       case OP_JMP: {

+ 16 - 8
ldo.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.c,v 2.192 2018/02/07 15:55:18 roberto Exp roberto $
+** $Id: ldo.c,v 2.193 2018/02/09 15:16:06 roberto Exp roberto $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -310,11 +310,19 @@ void luaD_hookcall (lua_State *L, CallInfo *ci) {
 }
 
 
-void luaD_rethook (lua_State *L, CallInfo *ci) {
-  if (isLuacode(ci))
+static void rethook (lua_State *L, CallInfo *ci) {
+  int delta = 0;
+  if (isLuacode(ci)) {
+    Proto *p = clLvalue(s2v(ci->func))->p;
+    if (p->is_vararg)
+      delta = ci->u.l.nextraargs + p->numparams + 1;
     L->top = ci->top;  /* prepare top */
-  if (L->hookmask & LUA_MASKRET)  /* is return hook on? */
+  }
+  if (L->hookmask & LUA_MASKRET) {  /* is return hook on? */
+    ci->func += delta;  /* if vararg, back to virtual 'func' */
     luaD_hook(L, LUA_HOOKRET, -1);  /* call it */
+    ci->func -= delta;
+  }
   if (isLua(ci->previous))
     L->oldpc = ci->previous->u.l.savedpc;  /* update 'oldpc' */
 }
@@ -343,8 +351,8 @@ void luaD_tryfuncTM (lua_State *L, StkId func) {
 ** expressions, multiple results for tail calls/single parameters)
 ** separated.
 */
-void luaD_moveresults (lua_State *L, StkId firstResult, StkId res,
-                                     int nres, int wanted) {
+static void moveresults (lua_State *L, StkId firstResult, StkId res,
+                                       int nres, int wanted) {
   switch (wanted) {  /* handle typical cases separately */
     case 0: break;  /* nothing to move */
     case 1: {  /* one result needed */
@@ -387,12 +395,12 @@ void luaD_moveresults (lua_State *L, StkId firstResult, StkId res,
 void luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) {
   if (L->hookmask) {
     ptrdiff_t fr = savestack(L, firstResult);  /* hook may change stack */
-    luaD_rethook(L, ci);
+    rethook(L, ci);
     firstResult = restorestack(L, fr);
   }
   L->ci = ci->previous;  /* back to caller */
   /* move results to proper place */
-  luaD_moveresults(L, firstResult, ci->func, nres, ci->nresults);
+  moveresults(L, firstResult, ci->func, nres, ci->nresults);
 }
 
 

+ 1 - 4
ldo.h

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.h,v 2.40 2018/02/06 19:16:56 roberto Exp roberto $
+** $Id: ldo.h,v 2.41 2018/02/09 15:16:06 roberto Exp roberto $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -62,10 +62,7 @@ LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
                                         ptrdiff_t oldtop, ptrdiff_t ef);
 LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult,
                                           int nres);
-LUAI_FUNC void luaD_rethook (lua_State *L, CallInfo *ci);
 LUAI_FUNC int luaD_reallocstack (lua_State *L, int newsize, int raiseerror);
-LUAI_FUNC void luaD_moveresults (lua_State *L, StkId firstResult, StkId res,
-                                               int nres, int wanted);
 LUAI_FUNC int luaD_growstack (lua_State *L, int n, int raiseerror);
 LUAI_FUNC void luaD_shrinkstack (lua_State *L);
 LUAI_FUNC void luaD_inctop (lua_State *L);

+ 1 - 3
lopcodes.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.c,v 1.76 2018/02/07 15:18:04 roberto Exp roberto $
+** $Id: lopcodes.c,v 1.77 2018/02/09 15:16:06 roberto Exp roberto $
 ** Opcodes for Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -80,7 +80,6 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
   "CALL",
   "TAILCALL",
   "RETURN",
-  "RETVARARG",
   "RETURN0",
   "RETURN1",
   "FORLOOP1",
@@ -162,7 +161,6 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
  ,opmode(1, 1, 0, 1, iABC)		/* OP_CALL */
  ,opmode(1, 1, 0, 1, iABC)		/* OP_TAILCALL */
  ,opmode(0, 1, 0, 0, iABC)		/* OP_RETURN */
- ,opmode(0, 1, 0, 0, iABC)		/* OP_RETVARARG */
  ,opmode(0, 0, 0, 0, iABC)		/* OP_RETURN0 */
  ,opmode(0, 0, 0, 0, iABC)		/* OP_RETURN1 */
  ,opmode(0, 0, 0, 1, iABx)		/* OP_FORLOOP1 */

+ 12 - 10
lopcodes.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.h,v 1.186 2018/02/07 15:18:04 roberto Exp roberto $
+** $Id: lopcodes.h,v 1.187 2018/02/09 15:16:06 roberto Exp roberto $
 ** Opcodes for Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -267,8 +267,7 @@ 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_RETVARARG,/*	A B	return R(A), ... ,R(A+B-2)	(see note)	*/
+OP_RETURN,/*	A B C	return R(A), ... ,R(A+B-2)	(see note)	*/
 OP_RETURN0,/*	  	return 						*/
 OP_RETURN1,/*	A 	return R(A)					*/
 
@@ -302,14 +301,13 @@ OP_EXTRAARG/*	Ax	extra (larger) argument for previous opcode	*/
 /*===========================================================================
   Notes:
   (*) In OP_CALL, if (B == 0) then B = top. If (C == 0), then 'top' is
-  set to last_result+1, so next open instruction (OP_CALL, OP_RETURN,
+  set to last_result+1, so next open instruction (OP_CALL, OP_RETURN*,
   OP_SETLIST) may use 'top'.
 
   (*) In OP_VARARG, if (C == 0) then use actual number of varargs and
   set top (like in OP_CALL with C == 0).
 
-  (*) In OP_RETURN/OP_RETVARARG, if (B == 0) then return up to 'top'.
-  (OP_RETVARARG is the return instruction for vararg functions.)
+  (*) In OP_RETURN, if (B == 0) then return up to 'top'.
 
   (*) In OP_SETLIST, if (B == 0) then real B = 'top'; if (C == 0) then
   next 'instruction' is EXTRAARG(real C).
@@ -326,9 +324,11 @@ OP_EXTRAARG/*	Ax	extra (larger) argument for previous opcode	*/
 
   (*) All 'skips' (pc++) assume that next instruction is a jump.
 
-  (*) In instructions ending a function (OP_RETURN*, OP_TAILCALL), k
-  specifies that the function builds upvalues, which may need to be
-  closed.
+  (*) In instructions OP_RETURN/OP_TAILCALL, 'k' specifies that the
+  function either builds upvalues, which may need to be closed, or is
+  vararg, which must be corrected before returning. When 'k' is true,
+  C > 0 means the function is vararg and (C - 1) is its number of
+  fixed parameters.
 
 ===========================================================================*/
 
@@ -351,7 +351,9 @@ LUAI_DDEC const lu_byte luaP_opmodes[NUM_OPCODES];
 #define testOTMode(m)	(luaP_opmodes[m] & (1 << 6))
 
 /* "out top" (set top for next instruction) */
-#define isOT(i)		(testOTMode(GET_OPCODE(i)) && GETARG_C(i) == 0)
+#define isOT(i)  \
+	((testOTMode(GET_OPCODE(i)) && GETARG_C(i) == 0) || \
+          GET_OPCODE(i) == OP_TAILCALL)
 
 /* "in top" (uses top from previous instruction) */
 #define isIT(i)		(testITMode(GET_OPCODE(i)) && GETARG_B(i) == 0)

+ 6 - 4
ltm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ltm.c,v 2.59 2018/02/07 15:18:04 roberto Exp roberto $
+** $Id: ltm.c,v 2.60 2018/02/09 15:16:06 roberto Exp roberto $
 ** Tag methods
 ** See Copyright Notice in lua.h
 */
@@ -222,10 +222,12 @@ void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci) {
   int nextra = actual - nfixparams;  /* number of extra arguments */
   ci->u.l.nextraargs = nextra;
   checkstackGC(L, nfixparams + 1);
-  /* copy function and fixed parameters to the top of the stack */
-  for (i = 0; i <= nfixparams; i++) {
+  /* copy function to the top of the stack */
+  setobjs2s(L, L->top++, ci->func);
+  /* move fixed parameters to the top of the stack */
+  for (i = 1; i <= nfixparams; i++) {
     setobjs2s(L, L->top++, ci->func + i);
-    setnilvalue(s2v(ci->func + i));  /* erase original copy (for GC) */
+    setnilvalue(s2v(ci->func + i));  /* erase original parameter (for GC) */
   }
   ci->func += actual + 1;
   ci->top += actual + 1;

+ 26 - 34
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 2.338 2018/02/07 15:18:04 roberto Exp roberto $
+** $Id: lvm.c,v 2.339 2018/02/09 15:16:06 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -1493,23 +1493,35 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
       }
       vmcase(OP_TAILCALL) {
         int b = GETARG_B(i);  /* number of arguments + 1 (function) */
+        int delta = 0;  /* virtual 'func' - real 'func' (vararg functions) */
         if (b != 0)
           L->top = ra + b;
         else  /* previous instruction set top */
           b = cast_int(L->top - ra);
-        lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
+        savepc(ci);
+        if (TESTARG_k(i)) {
+          int nparams1 = GETARG_C(i);
+          if (nparams1)  /* vararg function? */
+            delta = ci->u.l.nextraargs + nparams1;
+          luaF_close(L, base);  /* close upvalues from current call */
+        }
         if (!ttisfunction(vra)) {  /* not a function? */
-          ProtectNT(luaD_tryfuncTM(L, ra));  /* try '__call' metamethod */
+          luaD_tryfuncTM(L, ra);  /* try '__call' metamethod */
           b++;  /* there is now one extra argument */
         }
-        if (TESTARG_k(i))
-          luaF_close(L, base);  /* close upvalues from current call */
         if (!ttisLclosure(vra)) {  /* C function? */
-          ProtectNT(luaD_call(L, ra, LUA_MULTRET));  /* call it */
+          luaD_call(L, ra, LUA_MULTRET);  /* call it */
+          updatetrap(ci);
+          if (trap) {  /* stack may have been relocated */
+            updatebase(ci);
+            ra = RA(i);
+          }
+          ci->func -= delta;
+          luaD_poscall(L, ci, ra, cast_int(L->top - ra));
+          return;
         }
         else {  /* Lua tail call */
-          if (cl->p->is_vararg)
-            ci->func -= cl->p->numparams + ci->u.l.nextraargs + 1;
+          ci->func -= delta;
           luaD_pretailcall(L, ci, ra, b);  /* prepare call frame */
           goto tailcall;
         }
@@ -1518,34 +1530,16 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
       vmcase(OP_RETURN) {
         int b = GETARG_B(i);
         int n = (b != 0 ? b - 1 : cast_int(L->top - ra));
-        if (TESTARG_k(i))
-          luaF_close(L, base);
-        halfProtect(luaD_poscall(L, ci, ra, n));
-        return;
-      }
-      vmcase(OP_RETVARARG) {
-        int b = GETARG_B(i);
-        int nparams = GETARG_C(i);
-        int nres = (b != 0 ? b - 1 : cast_int(L->top - ra));
-        int delta = ci->u.l.nextraargs + nparams + 2;
-        if (TESTARG_k(i))
-          luaF_close(L, base);
-        savepc(L);
-        /* code similar to 'luaD_poscall', but with a delta */
-        if (L->hookmask) {
-          luaD_rethook(L, ci);
-          if (ci->u.l.trap) {
-            updatebase(ci);
-            ra = RA(i);
-          }
+        if (TESTARG_k(i)) {
+          int nparams1 = GETARG_C(i);
+          if (nparams1)  /* vararg function? */
+            ci->func -= ci->u.l.nextraargs + nparams1;
+          luaF_close(L, base);  /* there may be open upvalues */
         }
-        L->ci = ci->previous;  /* back to caller */
-        luaD_moveresults(L, ra, base - delta, nres, ci->nresults);
+        halfProtect(luaD_poscall(L, ci, ra, n));
         return;
       }
       vmcase(OP_RETURN0) {
-        if (TESTARG_k(i))
-          luaF_close(L, base);
         if (L->hookmask)
           halfProtect(luaD_poscall(L, ci, ra, 0));  /* no hurry... */
         else {
@@ -1558,8 +1552,6 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
         return;
       }
       vmcase(OP_RETURN1) {
-        if (TESTARG_k(i))
-          luaF_close(L, base);
         if (L->hookmask)
           halfProtect(luaD_poscall(L, ci, ra, 1));  /* no hurry... */
         else {