Просмотр исходного кода

Vararg table

Not yet optimized nor documented.
Roberto I 4 месяцев назад
Родитель
Сommit
140b672e2e
9 измененных файлов с 80 добавлено и 31 удалено
  1. 4 2
      lobject.h
  2. 1 1
      lopcodes.h
  3. 19 10
      lparser.c
  4. 5 4
      lparser.h
  5. 39 6
      ltm.c
  6. 2 2
      ltm.h
  7. 2 1
      lundump.c
  8. 1 1
      lvm.c
  9. 7 4
      testes/vararg.lua

+ 4 - 2
lobject.h

@@ -583,8 +583,10 @@ typedef struct AbsLineInfo {
 /*
 /*
 ** Flags in Prototypes
 ** Flags in Prototypes
 */
 */
-#define PF_ISVARARG	1
-#define PF_FIXED	2  /* prototype has parts in fixed memory */
+#define PF_ISVARARG	1  /* function is vararg */
+#define PF_VATAB	2  /* function is vararg with table */
+#define PF_VAPTAB	4  /* function is vararg with pseudo-table */
+#define PF_FIXED	8  /* prototype has parts in fixed memory */
 
 
 
 
 /*
 /*

+ 1 - 1
lopcodes.h

@@ -338,7 +338,7 @@ OP_CLOSURE,/*	A Bx	R[A] := closure(KPROTO[Bx])			*/
 
 
 OP_VARARG,/*	A C	R[A], R[A+1], ..., R[A+C-2] = vararg		*/
 OP_VARARG,/*	A C	R[A], R[A+1], ..., R[A+C-2] = vararg		*/
 
 
-OP_VARARGPREP,/*A	(adjust vararg parameters)			*/
+OP_VARARGPREP,/* 	(adjust vararg parameters)			*/
 
 
 OP_EXTRAARG/*	Ax	extra (larger) argument for previous opcode	*/
 OP_EXTRAARG/*	Ax	extra (larger) argument for previous opcode	*/
 } OpCode;
 } OpCode;

+ 19 - 10
lparser.c

@@ -1041,9 +1041,10 @@ static void constructor (LexState *ls, expdesc *t) {
 /* }====================================================================== */
 /* }====================================================================== */
 
 
 
 
-static void setvararg (FuncState *fs, int nparams) {
-  fs->f->flag |= PF_ISVARARG;
-  luaK_codeABC(fs, OP_VARARGPREP, nparams, 0, 0);
+static void setvararg (FuncState *fs, int kind) {
+  lua_assert(kind & PF_ISVARARG);
+  fs->f->flag |= cast_byte(kind);
+  luaK_codeABC(fs, OP_VARARGPREP, 0, 0, 0);
 }
 }
 
 
 
 
@@ -1052,7 +1053,7 @@ static void parlist (LexState *ls) {
   FuncState *fs = ls->fs;
   FuncState *fs = ls->fs;
   Proto *f = fs->f;
   Proto *f = fs->f;
   int nparams = 0;
   int nparams = 0;
-  int isvararg = 0;
+  int varargk = 0;
   if (ls->t.token != ')') {  /* is 'parlist' not empty? */
   if (ls->t.token != ')') {  /* is 'parlist' not empty? */
     do {
     do {
       switch (ls->t.token) {
       switch (ls->t.token) {
@@ -1062,19 +1063,27 @@ static void parlist (LexState *ls) {
           break;
           break;
         }
         }
         case TK_DOTS: {
         case TK_DOTS: {
+          varargk |= PF_ISVARARG;
           luaX_next(ls);
           luaX_next(ls);
-          isvararg = 1;
+          if (testnext(ls, '=')) {
+            new_varkind(ls, str_checkname(ls), RDKVATAB);
+            varargk |= PF_VATAB;
+          }
           break;
           break;
         }
         }
         default: luaX_syntaxerror(ls, "<name> or '...' expected");
         default: luaX_syntaxerror(ls, "<name> or '...' expected");
       }
       }
-    } while (!isvararg && testnext(ls, ','));
+    } while (!varargk && testnext(ls, ','));
   }
   }
   adjustlocalvars(ls, nparams);
   adjustlocalvars(ls, nparams);
   f->numparams = cast_byte(fs->nactvar);
   f->numparams = cast_byte(fs->nactvar);
-  if (isvararg)
-    setvararg(fs, f->numparams);  /* declared vararg */
-  luaK_reserveregs(fs, fs->nactvar);  /* reserve registers for parameters */
+  if (varargk != 0) {
+    setvararg(fs, varargk);  /* declared vararg */
+    if (varargk & PF_VATAB)
+      adjustlocalvars(ls, 1);  /* vararg table */
+  }
+  /* reserve registers for parameters (and vararg variable, if present) */
+  luaK_reserveregs(fs, fs->nactvar);
 }
 }
 
 
 
 
@@ -2099,7 +2108,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
   BlockCnt bl;
   BlockCnt bl;
   Upvaldesc *env;
   Upvaldesc *env;
   open_func(ls, fs, &bl);
   open_func(ls, fs, &bl);
-  setvararg(fs, 0);  /* main function is always declared vararg */
+  setvararg(fs, PF_ISVARARG);  /* main function is always vararg */
   env = allocupvalue(fs);  /* ...set environment upvalue */
   env = allocupvalue(fs);  /* ...set environment upvalue */
   env->instack = 1;
   env->instack = 1;
   env->idx = 0;
   env->idx = 0;

+ 5 - 4
lparser.h

@@ -97,10 +97,11 @@ typedef struct expdesc {
 /* kinds of variables */
 /* kinds of variables */
 #define VDKREG		0   /* regular local */
 #define VDKREG		0   /* regular local */
 #define RDKCONST	1   /* local constant */
 #define RDKCONST	1   /* local constant */
-#define RDKTOCLOSE	2   /* to-be-closed */
-#define RDKCTC		3   /* local compile-time constant */
-#define GDKREG		4   /* regular global */
-#define GDKCONST	5   /* global constant */
+#define RDKVATAB	2   /* vararg table */
+#define RDKTOCLOSE	3   /* to-be-closed */
+#define RDKCTC		4   /* local compile-time constant */
+#define GDKREG		5   /* regular global */
+#define GDKCONST	6   /* global constant */
 
 
 /* variables that live in registers */
 /* variables that live in registers */
 #define varinreg(v)	((v)->vd.kind <= RDKTOCLOSE)
 #define varinreg(v)	((v)->vd.kind <= RDKTOCLOSE)

+ 39 - 6
ltm.c

@@ -224,11 +224,38 @@ int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
 }
 }
 
 
 
 
-void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
-                         const Proto *p) {
+/*
+** Create a vararg table at the top of the stack, with 'n' elements
+** starting at 'f'.
+*/
+static void createvarargtab (lua_State *L, StkId f, int n) {
   int i;
   int i;
-  int actual = cast_int(L->top.p - ci->func.p) - 1;  /* number of arguments */
-  int nextra = actual - nfixparams;  /* number of extra arguments */
+  TValue key, value;
+  Table *t = luaH_new(L);
+  sethvalue(L, s2v(L->top.p), t);
+  L->top.p++;
+  luaH_resize(L, t, cast_uint(n), 1);
+  setsvalue(L, &key, luaS_new(L, "n"));  /* key is "n" */
+  setivalue(&value, n);  /* value is n */
+  /* No need to anchor the key: Due to the resize, the next operation
+     cannot trigger a garbage collection */
+  luaH_set(L, t, &key, &value);  /* t.n = n */
+  for (i = 0; i < n; i++)
+    luaH_setint(L, t, i + 1, s2v(f + i));
+}
+
+
+/*
+** initial stack:  func arg1 ... argn extra1 ...
+**                 ^ ci->func                    ^ L->top
+** final stack: func nil ... nil extra1 ... func arg1 ... argn
+**                                          ^ ci->func         ^ L->top
+*/
+void luaT_adjustvarargs (lua_State *L, CallInfo *ci, const Proto *p) {
+  int i;
+  int totalargs = cast_int(L->top.p - ci->func.p) - 1;
+  int nfixparams = p->numparams;
+  int nextra = totalargs - nfixparams;  /* number of extra arguments */
   ci->u.l.nextraargs = nextra;
   ci->u.l.nextraargs = nextra;
   luaD_checkstack(L, p->maxstacksize + 1);
   luaD_checkstack(L, p->maxstacksize + 1);
   /* copy function to the top of the stack */
   /* copy function to the top of the stack */
@@ -238,8 +265,14 @@ void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
     setobjs2s(L, L->top.p++, ci->func.p + i);
     setobjs2s(L, L->top.p++, ci->func.p + i);
     setnilvalue(s2v(ci->func.p + i));  /* erase original parameter (for GC) */
     setnilvalue(s2v(ci->func.p + i));  /* erase original parameter (for GC) */
   }
   }
-  ci->func.p += actual + 1;
-  ci->top.p += actual + 1;
+  if (p->flag & (PF_VAPTAB | PF_VATAB)) {  /* is there a vararg table? */
+    if (p->flag & PF_VAPTAB)  /* is vararg table fake? */
+      setnilvalue(s2v(L->top.p));  /* initialize it */
+    else
+      createvarargtab(L, ci->func.p + nfixparams + 1, nextra);
+  }
+  ci->func.p += totalargs + 1;
+  ci->top.p += totalargs + 1;
   lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
   lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
 }
 }
 
 

+ 2 - 2
ltm.h

@@ -95,8 +95,8 @@ LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1,
 LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
 LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
                                  int inv, int isfloat, TMS event);
                                  int inv, int isfloat, TMS event);
 
 
-LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
-                                   struct CallInfo *ci, const Proto *p);
+LUAI_FUNC void luaT_adjustvarargs (lua_State *L, struct CallInfo *ci,
+                                                 const Proto *p);
 LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
 LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
                                               StkId where, int wanted);
                                               StkId where, int wanted);
 
 

+ 2 - 1
lundump.c

@@ -327,7 +327,8 @@ static void loadFunction (LoadState *S, Proto *f) {
   f->linedefined = loadInt(S);
   f->linedefined = loadInt(S);
   f->lastlinedefined = loadInt(S);
   f->lastlinedefined = loadInt(S);
   f->numparams = loadByte(S);
   f->numparams = loadByte(S);
-  f->flag = loadByte(S) & PF_ISVARARG;  /* get only the meaningful flags */
+  /* get only the meaningful flags */
+  f->flag = cast_byte(loadByte(S) & ~PF_FIXED);
   if (S->fixed)
   if (S->fixed)
     f->flag |= PF_FIXED;  /* signal that code is fixed */
     f->flag |= PF_FIXED;  /* signal that code is fixed */
   f->maxstacksize = loadByte(S);
   f->maxstacksize = loadByte(S);

+ 1 - 1
lvm.c

@@ -1927,7 +1927,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
         vmbreak;
         vmbreak;
       }
       }
       vmcase(OP_VARARGPREP) {
       vmcase(OP_VARARGPREP) {
-        ProtectNT(luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p));
+        ProtectNT(luaT_adjustvarargs(L, ci, cl->p));
         if (l_unlikely(trap)) {  /* previous "Protect" updated trap */
         if (l_unlikely(trap)) {  /* previous "Protect" updated trap */
           luaD_hookcall(L, ci);
           luaD_hookcall(L, ci);
           L->oldpc = 1;  /* next opcode will be seen as a "new" line */
           L->oldpc = 1;  /* next opcode will be seen as a "new" line */

+ 7 - 4
testes/vararg.lua

@@ -3,9 +3,12 @@
 
 
 print('testing vararg')
 print('testing vararg')
 
 
-local function f (a, ...)
+local function f (a, ...=t)
   local x = {n = select('#', ...), ...}
   local x = {n = select('#', ...), ...}
-  for i = 1, x.n do assert(a[i] == x[i]) end
+  assert(x.n == t.n)
+  for i = 1, x.n do
+    assert(a[i] == x[i] and x[i] == t[i])
+  end
   return x.n
   return x.n
 end
 end
 
 
@@ -17,7 +20,7 @@ local function c12 (...)
   return res, 2
   return res, 2
 end
 end
 
 
-local function vararg (...) return {n = select('#', ...), ...} end
+local function vararg (...=t) return t end
 
 
 local call = function (f, args) return f(table.unpack(args, 1, args.n)) end
 local call = function (f, args) return f(table.unpack(args, 1, args.n)) end
 
 
@@ -99,7 +102,7 @@ assert(a==nil and b==nil and c==nil and d==nil and e==nil)
 
 
 
 
 -- varargs for main chunks
 -- varargs for main chunks
-local f = load[[ return {...} ]]
+local f = assert(load[[ return {...} ]])
 local x = f(2,3)
 local x = f(2,3)
 assert(x[1] == 2 and x[2] == 3 and x[3] == undef)
 assert(x[1] == 2 and x[2] == 3 and x[3] == undef)