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

Varag parameter is a new kind of variable

To allow some optimizations on its use.
Roberto I 4 месяцев назад
Родитель
Сommit
8fb1af0e33
7 измененных файлов с 65 добавлено и 16 удалено
  1. 12 0
      lcode.c
  2. 1 0
      lcode.h
  3. 2 2
      lobject.h
  4. 17 9
      lparser.c
  5. 3 1
      lparser.h
  6. 4 4
      ltm.c
  7. 26 0
      testes/vararg.lua

+ 12 - 0
lcode.c

@@ -785,6 +785,15 @@ void luaK_setoneret (FuncState *fs, expdesc *e) {
   }
 }
 
+/*
+** Change a vararg parameter into a regular local variable
+*/
+void luaK_vapar2local (FuncState *fs, expdesc *var) {
+  fs->f->flag |= PF_VATAB;  /* function will need a vararg table */
+  /* now a vararg parameter is equivalent to a regular local variable */
+  var->k = VLOCAL;
+}
+
 
 /*
 ** Ensure that expression 'e' is not a variable (nor a <const>).
@@ -796,6 +805,9 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
       const2exp(const2val(fs, e), e);
       break;
     }
+    case VVARGVAR: {
+      luaK_vapar2local(fs, e);  /* turn it into a local variable */
+    }  /* FALLTHROUGH */
     case VLOCAL: {  /* already in a register */
       int temp = e->u.var.ridx;
       e->u.info = temp;  /* (can't do a direct assignment; values overlap) */

+ 1 - 0
lcode.h

@@ -71,6 +71,7 @@ LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
 LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
 LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
 LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n);
+LUAI_FUNC void luaK_vapar2local (FuncState *fs, expdesc *var);
 LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);
 LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
 LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);

+ 2 - 2
lobject.h

@@ -584,8 +584,8 @@ typedef struct AbsLineInfo {
 ** Flags in Prototypes
 */
 #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_VAVAR	2  /* function has vararg parameter */
+#define PF_VATAB	4  /* function has vararg table */
 #define PF_FIXED	8  /* prototype has parts in fixed memory */
 
 

+ 17 - 9
lparser.c

@@ -289,7 +289,7 @@ static void check_readonly (LexState *ls, expdesc *e) {
       varname = ls->dyd->actvar.arr[e->u.info].vd.name;
       break;
     }
-    case VLOCAL: {
+    case VLOCAL: case VVARGVAR: {
       Vardesc *vardesc = getlocalvardesc(fs, e->u.var.vidx);
       if (vardesc->vd.kind != VDKREG)  /* not a regular variable? */
         varname = vardesc->vd.name;
@@ -426,8 +426,11 @@ static int searchvar (FuncState *fs, TString *n, expdesc *var) {
     else if (eqstr(n, vd->vd.name)) {  /* found? */
       if (vd->vd.kind == RDKCTC)  /* compile-time constant? */
         init_exp(var, VCONST, fs->firstlocal + i);
-      else  /* local variable */
+      else {  /* local variable */
         init_var(fs, var, i);
+        if (vd->vd.kind == RDKVAVAR)  /* vararg parameter? */
+          var->k = VVARGVAR;
+      }
       return cast_int(var->k);
     }
   }
@@ -467,8 +470,13 @@ static void marktobeclosed (FuncState *fs) {
 static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
   int v = searchvar(fs, n, var);  /* look up variables at current level */
   if (v >= 0) {  /* found? */
-    if (v == VLOCAL && !base)
-      markupval(fs, var->u.var.vidx);  /* local will be used as an upval */
+    if (!base) {
+      if (var->k == VVARGVAR)  /* vararg parameter? */
+        luaK_vapar2local(fs, var);  /* change it to a regular local */
+      if (var->k == VLOCAL)
+        markupval(fs, var->u.var.vidx);  /* will be used as an upvalue */
+    }
+    /* else nothing else to be done */
   }
   else {  /* not found at current level; try upvalues */
     int idx = searchupvalue(fs, n);  /* try existing upvalues */
@@ -1066,8 +1074,8 @@ static void parlist (LexState *ls) {
           varargk |= PF_ISVARARG;
           luaX_next(ls);
           if (testnext(ls, '=')) {
-            new_varkind(ls, str_checkname(ls), RDKVATAB);
-            varargk |= PF_VATAB;
+            new_varkind(ls, str_checkname(ls), RDKVAVAR);
+            varargk |= PF_VAVAR;
           }
           break;
         }
@@ -1079,10 +1087,10 @@ static void parlist (LexState *ls) {
   f->numparams = cast_byte(fs->nactvar);
   if (varargk != 0) {
     setvararg(fs, varargk);  /* declared vararg */
-    if (varargk & PF_VATAB)
-      adjustlocalvars(ls, 1);  /* vararg table */
+    if (varargk & PF_VAVAR)
+      adjustlocalvars(ls, 1);  /* vararg parameter */
   }
-  /* reserve registers for parameters (and vararg variable, if present) */
+  /* reserve registers for parameters (plus vararg parameter, if present) */
   luaK_reserveregs(fs, fs->nactvar);
 }
 

+ 3 - 1
lparser.h

@@ -37,6 +37,8 @@ typedef enum {
                  info = result register */
   VLOCAL,  /* local variable; var.ridx = register index;
               var.vidx = relative index in 'actvar.arr'  */
+  VVARGVAR,  /* vararg parameter; var.ridx = register index;
+              var.vidx = relative index in 'actvar.arr'  */
   VGLOBAL,  /* global variable;
                info = relative index in 'actvar.arr' (or -1 for
                       implicit declaration) */
@@ -97,7 +99,7 @@ typedef struct expdesc {
 /* kinds of variables */
 #define VDKREG		0   /* regular local */
 #define RDKCONST	1   /* local constant */
-#define RDKVATAB	2   /* vararg table */
+#define RDKVAVAR	2   /* vararg parameter */
 #define RDKTOCLOSE	3   /* to-be-closed */
 #define RDKCTC		4   /* local compile-time constant */
 #define GDKREG		5   /* regular global */

+ 4 - 4
ltm.c

@@ -265,11 +265,11 @@ void luaT_adjustvarargs (lua_State *L, CallInfo *ci, const Proto *p) {
     setobjs2s(L, L->top.p++, ci->func.p + i);
     setnilvalue(s2v(ci->func.p + i));  /* erase original parameter (for GC) */
   }
-  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
+  if (p->flag & PF_VAVAR) {  /* is there a vararg parameter? */
+    if (p->flag & PF_VATAB)  /* does it need a vararg table? */
       createvarargtab(L, ci->func.p + nfixparams + 1, nextra);
+    else  /* no table; set parameter to nil */
+      setnilvalue(s2v(L->top.p));
   }
   ci->func.p += totalargs + 1;
   ci->top.p += totalargs + 1;

+ 26 - 0
testes/vararg.lua

@@ -150,5 +150,31 @@ do
   local a, b = g()
   assert(a == nil and b == 2)
 end
+
+
+do  -- vararg parameter used in nested functions
+  local function foo (... = tab1)
+    return function (... = tab2)
+      return {tab1, tab2}
+    end
+  end
+  local f = foo(10, 20, 30)
+  local t = f("a", "b")
+  assert(t[1].n == 3 and t[1][1] == 10)
+  assert(t[2].n == 2 and t[2][1] == "a")
+end
+
+do  -- vararg parameter is read-only
+  local st, msg = load("return function (... = t) t = 10 end")
+  assert(string.find(msg, "const variable 't'"))
+
+  local st, msg = load[[
+    local function foo (... = extra)
+      return function (...) extra = nil end
+    end
+  ]]
+  assert(string.find(msg, "const variable 'extra'"))
+end
+
 print('OK')