Переглянути джерело

vararg back to '...' (but with another implementation)
new implementation should have zero overhead for non-vararg functions

Roberto Ierusalimschy 7 роки тому
батько
коміт
b1379936cf
11 змінених файлів з 133 додано та 110 видалено
  1. 13 13
      lcode.c
  2. 21 5
      ldebug.c
  3. 17 20
      ldo.c
  4. 9 1
      ldo.h
  5. 3 1
      lopcodes.c
  6. 6 4
      lopcodes.h
  7. 6 16
      lparser.c
  8. 2 1
      lstate.h
  9. 23 32
      ltm.c
  10. 6 4
      ltm.h
  11. 27 13
      lvm.c

+ 13 - 13
lcode.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.c,v 2.151 2018/01/27 16:56:33 roberto Exp roberto $
+** $Id: lcode.c,v 2.152 2018/01/28 15:13:26 roberto Exp roberto $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -31,7 +31,7 @@
 
 
 /* Maximum number of registers in a Lua function (must fit in 8 bits) */
-#define MAXREGS		255
+#define MAXREGS		254
 
 
 #define hasjumps(e)	((e)->t != (e)->f)
@@ -157,17 +157,17 @@ int luaK_jump (FuncState *fs) {
 ** Code a 'return' instruction
 */
 void luaK_ret (FuncState *fs, int first, int nret) {
-  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;
+  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;
+    }
   }
+  luaK_codeABC(fs, op, first, nret + 1, fs->f->numparams);
 }
 
 
@@ -1647,7 +1647,7 @@ void luaK_finish (FuncState *fs) {
     lua_assert(i == 0 || isOT(*(pc - 1)) == isIT(*pc));
     switch (GET_OPCODE(*pc)) {
       case OP_RETURN: case OP_RETURN0: case OP_RETURN1:
-      case OP_TAILCALL: {
+      case OP_RETVARARG: case OP_TAILCALL: {
         if (p->sizep > 0)
           SETARG_k(*pc, 1);  /* signal that they must close upvalues */
         break;

+ 21 - 5
ldebug.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldebug.c,v 2.152 2018/01/10 12:02:35 roberto Exp roberto $
+** $Id: ldebug.c,v 2.153 2018/02/06 19:16:56 roberto Exp roberto $
 ** Debug Interface
 ** See Copyright Notice in lua.h
 */
@@ -187,12 +187,28 @@ static const char *upvalname (Proto *p, int uv) {
 }
 
 
+static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
+  if (clLvalue(s2v(ci->func))->p->is_vararg) {
+    int nextra = ci->u.l.nextraargs;
+    if (n <= nextra) {
+      *pos = ci->func - nextra + (n - 1);
+      return "(*vararg)";  /* generic name for any vararg */
+    }
+  }
+  return NULL;  /* no such vararg */
+}
+
+
 static const char *findlocal (lua_State *L, CallInfo *ci, int n,
                               StkId *pos) {
   StkId base = ci->func + 1;
-  const char *name = (isLua(ci))
-                     ? luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci))
-                     : NULL;
+  const char *name = NULL;
+  if (isLua(ci)) {
+    if (n < 0)  /* access to vararg values? */
+      return findvararg(ci, -n, pos);
+    else
+      name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
+  }
   if (name == NULL) {  /* no 'standard' name? */
     StkId limit = (ci == L->ci) ? L->top : ci->next->func;
     if (limit - base >= n && n > 0)  /* is 'n' inside 'ci' stack? */
@@ -324,7 +340,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
         }
         else {
           ar->isvararg = f->l.p->is_vararg;
-          ar->nparams = f->l.p->numparams + f->l.p->is_vararg;
+          ar->nparams = f->l.p->numparams;
         }
         break;
       }

+ 17 - 20
ldo.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.c,v 2.191 2018/02/07 15:18:04 roberto Exp roberto $
+** $Id: ldo.c,v 2.192 2018/02/07 15:55:18 roberto Exp roberto $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -310,7 +310,7 @@ void luaD_hookcall (lua_State *L, CallInfo *ci) {
 }
 
 
-static void rethook (lua_State *L, CallInfo *ci) {
+void luaD_rethook (lua_State *L, CallInfo *ci) {
   if (isLuacode(ci))
     L->top = ci->top;  /* prepare top */
   if (L->hookmask & LUA_MASKRET)  /* is return hook on? */
@@ -343,8 +343,8 @@ void luaD_tryfuncTM (lua_State *L, StkId func) {
 ** expressions, multiple results for tail calls/single parameters)
 ** separated.
 */
-static void moveresults (lua_State *L, StkId firstResult, StkId res,
-                                       int nres, int wanted) {
+void luaD_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 */
@@ -382,27 +382,22 @@ static void moveresults (lua_State *L, StkId firstResult, StkId res,
 
 /*
 ** Finishes a function call: calls hook if necessary, removes CallInfo,
-** moves current number of results to proper place; returns 0 iff call
-** wanted multiple (variable number of) results.
+** moves current number of results to proper place.
 */
 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 */
-    rethook(L, ci);
+    luaD_rethook(L, ci);
     firstResult = restorestack(L, fr);
   }
   L->ci = ci->previous;  /* back to caller */
   /* move results to proper place */
-  moveresults(L, firstResult, ci->func, nres, ci->nresults);
+  luaD_moveresults(L, firstResult, ci->func, nres, ci->nresults);
 }
 
 
 
-#define next_ci(L)	(L->ci->next ? L->ci->next : luaE_extendCI(L))
-
-
-#define checkstackGC(L,fsize)  \
-	luaD_checkstackaux(L, (fsize), (void)0, luaC_checkGC(L))
+#define next_ci(L)  (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))
 
 
 /*
@@ -438,8 +433,6 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) {
 void luaD_call (lua_State *L, StkId func, int nresults) {
   lua_CFunction f;
   TValue *funcv = s2v(func);
-  CallInfo *ci = next_ci(L);
-  ci->nresults = nresults;
   switch (ttype(funcv)) {
     case LUA_TCCL:  /* C closure */
       f = clCvalue(funcv)->f;
@@ -448,12 +441,14 @@ void luaD_call (lua_State *L, StkId func, int nresults) {
       f = fvalue(funcv);
      Cfunc: {
       int n;  /* number of returns */
+      CallInfo *ci;
       checkstackp(L, LUA_MINSTACK, func);  /* ensure minimum stack size */
+      ci = next_ci(L);
+      ci->nresults = nresults;
       ci->callstatus = CIST_C;
       ci->top = L->top + LUA_MINSTACK;
       ci->func = func;
       lua_assert(ci->top <= L->stack_last);
-      L->ci = ci;  /* now 'enter' new function */
       if (L->hookmask & LUA_MASKCALL)
         luaD_hook(L, LUA_HOOKCALL, -1);
       lua_unlock(L);
@@ -464,18 +459,20 @@ void luaD_call (lua_State *L, StkId func, int nresults) {
       break;
     }
     case LUA_TLCL: {  /* Lua function */
+      CallInfo *ci;
       Proto *p = clLvalue(funcv)->p;
       int narg = cast_int(L->top - func) - 1;  /* number of real arguments */
       int nfixparams = p->numparams;
       int fsize = p->maxstacksize;  /* frame size */
-      ci->u.l.savedpc = p->code;  /* starting point */
       checkstackp(L, fsize, func);
-      for (; narg < nfixparams; narg++)
-        setnilvalue(s2v(L->top++));  /* complete missing arguments */
+      ci = next_ci(L);
+      ci->nresults = nresults;
+      ci->u.l.savedpc = p->code;  /* starting point */
       ci->callstatus = 0;
       ci->top = func + 1 + fsize;
       ci->func = func;
-      L->ci = ci;  /* now 'enter' new function */
+      for (; narg < nfixparams; narg++)
+        setnilvalue(s2v(L->top++));  /* complete missing arguments */
       lua_assert(ci->top <= L->stack_last);
       luaV_execute(L, ci);  /* run the function */
       break;

+ 9 - 1
ldo.h

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.h,v 2.39 2018/01/10 19:19:27 roberto Exp roberto $
+** $Id: ldo.h,v 2.40 2018/02/06 19:16:56 roberto Exp roberto $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -42,6 +42,11 @@
     p = restorestack(L, t__))  /* 'pos' part: restore 'p' */
 
 
+/* macro to check stack size and GC */
+#define checkstackGC(L,fsize)  \
+	luaD_checkstackaux(L, (fsize), (void)0, luaC_checkGC(L))
+
+
 /* type of protected functions, to be ran by 'runprotected' */
 typedef void (*Pfunc) (lua_State *L, void *ud);
 
@@ -57,7 +62,10 @@ 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);

+ 3 - 1
lopcodes.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.c,v 1.75 2017/12/22 14:16:46 roberto Exp roberto $
+** $Id: lopcodes.c,v 1.76 2018/02/07 15:18:04 roberto Exp roberto $
 ** Opcodes for Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -80,6 +80,7 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
   "CALL",
   "TAILCALL",
   "RETURN",
+  "RETVARARG",
   "RETURN0",
   "RETURN1",
   "FORLOOP1",
@@ -161,6 +162,7 @@ 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 */

+ 6 - 4
lopcodes.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.h,v 1.184 2018/01/28 15:13:26 roberto Exp roberto $
+** $Id: lopcodes.h,v 1.186 2018/02/07 15:18:04 roberto Exp roberto $
 ** Opcodes for Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -268,6 +268,7 @@ 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_RETURN0,/*	  	return 						*/
 OP_RETURN1,/*	A 	return R(A)					*/
 
@@ -286,7 +287,7 @@ OP_SETLIST,/*	A B C	R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B	*/
 
 OP_CLOSURE,/*	A Bx	R(A) := closure(KPROTO[Bx])			*/
 
-OP_VARARG,/*	A B C	R(A), R(A+1), ..., R(A+C-2) = vararg(B)		*/
+OP_VARARG,/*	A B C  	R(A), R(A+1), ..., R(A+C-2) = vararg		*/
 
 OP_PREPVARARG,/*A 	(adjust vararg parameters)			*/
 
@@ -305,9 +306,10 @@ OP_EXTRAARG/*	Ax	extra (larger) argument for previous opcode	*/
   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). B is the vararg parameter.
+  set top (like in OP_CALL with C == 0).
 
-  (*) In OP_RETURN, if (B == 0) then return up to 'top'.
+  (*) In OP_RETURN/OP_RETVARARG, if (B == 0) then return up to 'top'.
+  (OP_RETVARARG is the return instruction for vararg functions.)
 
   (*) In OP_SETLIST, if (B == 0) then real B = 'top'; if (C == 0) then
   next 'instruction' is EXTRAARG(real C).

+ 6 - 16
lparser.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lparser.c,v 2.175 2017/12/22 14:16:46 roberto Exp roberto $
+** $Id: lparser.c,v 2.176 2018/02/07 15:18:04 roberto Exp roberto $
 ** Lua Parser
 ** See Copyright Notice in lua.h
 */
@@ -568,6 +568,7 @@ static void close_func (LexState *ls) {
   Proto *f = fs->f;
   luaK_ret(fs, 0, 0);  /* final return */
   leaveblock(fs);
+  lua_assert(fs->bl == NULL);
   luaK_finish(fs);
   luaM_shrinkvector(L, f->code, f->sizecode, fs->pc, Instruction);
   luaM_shrinkvector(L, f->lineinfo, f->sizelineinfo, fs->pc, ls_byte);
@@ -577,7 +578,8 @@ static void close_func (LexState *ls) {
   luaM_shrinkvector(L, f->p, f->sizep, fs->np, Proto *);
   luaM_shrinkvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar);
   luaM_shrinkvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc);
-  lua_assert(fs->bl == NULL);
+  if (f->is_vararg)
+    f->maxstacksize++;  /* ensure space to copy the function */
   ls->fs = fs->prev;
   luaC_checkGC(L);
 }
@@ -781,11 +783,6 @@ static void parlist (LexState *ls) {
         }
         case TK_DOTS: {  /* param -> '...' */
           luaX_next(ls);
-          if (testnext(ls, '='))
-            new_localvar(ls, str_checkname(ls));
-          else
-            new_localvarliteral(ls, "_ARG");
-          nparams++;
           isvararg = 1;
           break;
         }
@@ -795,10 +792,8 @@ static void parlist (LexState *ls) {
   }
   adjustlocalvars(ls, nparams);
   f->numparams = cast_byte(fs->nactvar);
-  if (isvararg) {
-    f->numparams--;  /* exclude vararg parameter */
+  if (isvararg)
     setvararg(fs, f->numparams);  /* declared vararg */
-  }
   luaK_reserveregs(fs, fs->nactvar);  /* reserve registers for parameters */
 }
 
@@ -984,10 +979,9 @@ static void simpleexp (LexState *ls, expdesc *v) {
     }
     case TK_DOTS: {  /* vararg */
       FuncState *fs = ls->fs;
-      int lastparam = fs->f->numparams;
       check_condition(ls, fs->f->is_vararg,
                       "cannot use '...' outside a vararg function");
-      init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, lastparam, 1));
+      init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 0, 1));
       break;
     }
     case '{': {  /* constructor */
@@ -1703,10 +1697,6 @@ static void mainfunc (LexState *ls, FuncState *fs) {
   expdesc v;
   open_func(ls, fs, &bl);
   setvararg(fs, 0);  /* main function is always declared vararg */
-  fs->f->numparams = 0;
-  new_localvarliteral(ls, "_ARG");
-  adjustlocalvars(ls, 1);
-  luaK_reserveregs(fs, 1);  /* reserve register for vararg */
   init_exp(&v, VLOCAL, 0);  /* create and... */
   newupvalue(fs, ls->envn, &v);  /* ...set environment upvalue */
   luaX_next(ls);  /* read first token */

+ 2 - 1
lstate.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.h,v 2.152 2017/11/23 16:35:54 roberto Exp roberto $
+** $Id: lstate.h,v 2.153 2017/12/19 16:40:17 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -92,6 +92,7 @@ typedef struct CallInfo {
     struct {  /* only for Lua functions */
       const Instruction *savedpc;
       l_signalT trap;
+      int nextraargs;  /* # of extra arguments in vararg functions */
     } l;
     struct {  /* only for C functions */
       lua_KFunction k;  /* continuation in case of yields */

+ 23 - 32
ltm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ltm.c,v 2.58 2018/01/28 13:39:52 roberto Exp roberto $
+** $Id: ltm.c,v 2.59 2018/02/07 15:18:04 roberto Exp roberto $
 ** Tag methods
 ** See Copyright Notice in lua.h
 */
@@ -216,41 +216,32 @@ int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
 }
 
 
-void luaT_adjustvarargs (lua_State *L, int nfixparams, StkId base) {
+void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci) {
   int i;
-  Table *vtab;
-  TValue nname;
-  int actual = cast_int(L->top - base);  /* number of arguments */
+  int actual = cast_int(L->top - ci->func) - 1;  /* number of arguments */
   int nextra = actual - nfixparams;  /* number of extra arguments */
-  vtab = luaH_new(L);  /* create vararg table */
-  sethvalue2s(L, L->top, vtab);  /* anchor it for resizing */
-  L->top++;  /* space ensured by caller */
-  luaH_resize(L, vtab, nextra, 1);
-  for (i = 0; i < nextra; i++)  /* put extra arguments into vararg table */
-    setobj2n(L, &vtab->array[i], s2v(L->top - nextra + i - 1));
-  setsvalue(L, &nname, G(L)->nfield);  /* get field 'n' */
-  setivalue(luaH_set(L, vtab, &nname), nextra);  /* store counter there */
-  L->top -= nextra;  /* remove extra elements from the stack */
-  sethvalue2s(L, L->top - 1, vtab);  /* move table to new top */
-  luaC_checkGC(L);
+  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++) {
+    setobjs2s(L, L->top++, ci->func + i);
+    setnilvalue(s2v(ci->func + i));  /* erase original copy (for GC) */
+  }
+  ci->func += actual + 1;
+  ci->top += actual + 1;
 }
 
 
-void luaT_getvarargs (lua_State *L, TValue *t, StkId where, int wanted) {
-  if (!ttistable(t))
-    luaG_runerror(L, "'vararg' parameter is not a table");
-  else {
-    int i;
-    Table *h = hvalue(t);
-    if (wanted < 0) {  /* get all? */
-      const TValue *ns = luaH_getstr(h, G(L)->nfield);
-      int n = (ttisinteger(ns)) ? cast_int(ivalue(ns)) : 0;
-      wanted = n;
-      checkstackp(L, n, where);
-      L->top = where + n;
-    }
-    for (i = 0; i < wanted; i++)  /* get what is available */
-      setobj2s(L, where + i, luaH_getint(h, i + 1));
-    return;
+void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
+  int i;
+  int nextra = ci->u.l.nextraargs;
+  if (wanted < 0) {
+    wanted = nextra;  /* get all extra arguments available */
+    checkstackp(L, nextra, where);  /* ensure stack space */
+    L->top = where + nextra;  /* next instruction will need top */
   }
+  for (i = 0; i < wanted && i < nextra; i++)
+    setobjs2s(L, where + i, ci->func - nextra + i);
+  for (; i < wanted; i++)   /* complete required results with nil */
+    setnilvalue(s2v(where + i));
 }

+ 6 - 4
ltm.h

@@ -1,5 +1,5 @@
 /*
-** $Id: ltm.h,v 2.29 2018/01/28 13:39:52 roberto Exp roberto $
+** $Id: ltm.h,v 2.30 2018/02/07 15:18:04 roberto Exp roberto $
 ** Tag methods
 ** See Copyright Notice in lua.h
 */
@@ -9,6 +9,7 @@
 
 
 #include "lobject.h"
+#include "lstate.h"
 
 
 /*
@@ -77,9 +78,10 @@ LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1,
 LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
                                  int inv, TMS event);
 
-LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams, StkId base);
-LUAI_FUNC void luaT_getvarargs (lua_State *L, TValue *t, StkId where,
-                                int wanted);
+LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
+                                                 struct CallInfo *ci);
+LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
+                                              StkId where, int wanted);
 
 
 #endif

+ 27 - 13
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 2.337 2018/02/06 19:16:56 roberto Exp roberto $
+** $Id: lvm.c,v 2.338 2018/02/07 15:18:04 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -1506,14 +1506,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
           luaF_close(L, base);  /* close upvalues from current call */
         if (!ttisLclosure(vra)) {  /* C function? */
           ProtectNT(luaD_call(L, ra, LUA_MULTRET));  /* call it */
-          if (trap) {
-            updatebase(ci);
-            ra = RA(i);
-          }
-          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;
           luaD_pretailcall(L, ci, ra, b);  /* prepare call frame */
           goto tailcall;
         }
@@ -1521,11 +1517,30 @@ 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);
-        halfProtect(
-          luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra)))
-        );
+        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);
+          }
+        }
+        L->ci = ci->previous;  /* back to caller */
+        luaD_moveresults(L, ra, base - delta, nres, ci->nresults);
         return;
       }
       vmcase(OP_RETURN0) {
@@ -1702,12 +1717,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
       }
       vmcase(OP_VARARG) {
         int n = GETARG_C(i) - 1;  /* required results */
-        TValue *vtab = vRB(i);  /* vararg table */
-        Protect(luaT_getvarargs(L, vtab, ra, n));
+        ProtectNT(luaT_getvarargs(L, ci, ra, n));
         vmbreak;
       }
       vmcase(OP_PREPVARARG) {
-        luaT_adjustvarargs(L, GETARG_A(i), base);
+        luaT_adjustvarargs(L, GETARG_A(i), ci);
         updatetrap(ci);
         if (trap) {
           luaD_hookcall(L, ci);