aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto I <roberto@inf.puc-rio.br>2025-09-17 16:07:48 -0300
committerRoberto I <roberto@inf.puc-rio.br>2025-09-17 16:07:48 -0300
commit8fb1af0e33cd8688f57cd0e3ab86420a8cfe99bd (patch)
tree2c199de5e67f395a4f9c94fcfb2ef3f0dad8882a
parent140b672e2ee2ac842661ece4b48e1a64f0cd11ea (diff)
downloadlua-8fb1af0e33cd8688f57cd0e3ab86420a8cfe99bd.tar.gz
lua-8fb1af0e33cd8688f57cd0e3ab86420a8cfe99bd.tar.bz2
lua-8fb1af0e33cd8688f57cd0e3ab86420a8cfe99bd.zip
Varag parameter is a new kind of variable
To allow some optimizations on its use.
-rw-r--r--lcode.c12
-rw-r--r--lcode.h1
-rw-r--r--lobject.h4
-rw-r--r--lparser.c26
-rw-r--r--lparser.h4
-rw-r--r--ltm.c8
-rw-r--r--testes/vararg.lua26
7 files changed, 65 insertions, 16 deletions
diff --git a/lcode.c b/lcode.c
index cafe265e..f74223eb 100644
--- a/lcode.c
+++ b/lcode.c
@@ -785,6 +785,15 @@ void luaK_setoneret (FuncState *fs, expdesc *e) {
785 } 785 }
786} 786}
787 787
788/*
789** Change a vararg parameter into a regular local variable
790*/
791void luaK_vapar2local (FuncState *fs, expdesc *var) {
792 fs->f->flag |= PF_VATAB; /* function will need a vararg table */
793 /* now a vararg parameter is equivalent to a regular local variable */
794 var->k = VLOCAL;
795}
796
788 797
789/* 798/*
790** Ensure that expression 'e' is not a variable (nor a <const>). 799** Ensure that expression 'e' is not a variable (nor a <const>).
@@ -796,6 +805,9 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
796 const2exp(const2val(fs, e), e); 805 const2exp(const2val(fs, e), e);
797 break; 806 break;
798 } 807 }
808 case VVARGVAR: {
809 luaK_vapar2local(fs, e); /* turn it into a local variable */
810 } /* FALLTHROUGH */
799 case VLOCAL: { /* already in a register */ 811 case VLOCAL: { /* already in a register */
800 int temp = e->u.var.ridx; 812 int temp = e->u.var.ridx;
801 e->u.info = temp; /* (can't do a direct assignment; values overlap) */ 813 e->u.info = temp; /* (can't do a direct assignment; values overlap) */
diff --git a/lcode.h b/lcode.h
index 94fc2417..8c27bc92 100644
--- a/lcode.h
+++ b/lcode.h
@@ -71,6 +71,7 @@ LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
71LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); 71LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
72LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); 72LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
73LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n); 73LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n);
74LUAI_FUNC void luaK_vapar2local (FuncState *fs, expdesc *var);
74LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); 75LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);
75LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); 76LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
76LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); 77LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
diff --git a/lobject.h b/lobject.h
index a805dcbf..841ab5b9 100644
--- a/lobject.h
+++ b/lobject.h
@@ -584,8 +584,8 @@ typedef struct AbsLineInfo {
584** Flags in Prototypes 584** Flags in Prototypes
585*/ 585*/
586#define PF_ISVARARG 1 /* function is vararg */ 586#define PF_ISVARARG 1 /* function is vararg */
587#define PF_VATAB 2 /* function is vararg with table */ 587#define PF_VAVAR 2 /* function has vararg parameter */
588#define PF_VAPTAB 4 /* function is vararg with pseudo-table */ 588#define PF_VATAB 4 /* function has vararg table */
589#define PF_FIXED 8 /* prototype has parts in fixed memory */ 589#define PF_FIXED 8 /* prototype has parts in fixed memory */
590 590
591 591
diff --git a/lparser.c b/lparser.c
index f7e78793..8b909f3d 100644
--- a/lparser.c
+++ b/lparser.c
@@ -289,7 +289,7 @@ static void check_readonly (LexState *ls, expdesc *e) {
289 varname = ls->dyd->actvar.arr[e->u.info].vd.name; 289 varname = ls->dyd->actvar.arr[e->u.info].vd.name;
290 break; 290 break;
291 } 291 }
292 case VLOCAL: { 292 case VLOCAL: case VVARGVAR: {
293 Vardesc *vardesc = getlocalvardesc(fs, e->u.var.vidx); 293 Vardesc *vardesc = getlocalvardesc(fs, e->u.var.vidx);
294 if (vardesc->vd.kind != VDKREG) /* not a regular variable? */ 294 if (vardesc->vd.kind != VDKREG) /* not a regular variable? */
295 varname = vardesc->vd.name; 295 varname = vardesc->vd.name;
@@ -426,8 +426,11 @@ static int searchvar (FuncState *fs, TString *n, expdesc *var) {
426 else if (eqstr(n, vd->vd.name)) { /* found? */ 426 else if (eqstr(n, vd->vd.name)) { /* found? */
427 if (vd->vd.kind == RDKCTC) /* compile-time constant? */ 427 if (vd->vd.kind == RDKCTC) /* compile-time constant? */
428 init_exp(var, VCONST, fs->firstlocal + i); 428 init_exp(var, VCONST, fs->firstlocal + i);
429 else /* local variable */ 429 else { /* local variable */
430 init_var(fs, var, i); 430 init_var(fs, var, i);
431 if (vd->vd.kind == RDKVAVAR) /* vararg parameter? */
432 var->k = VVARGVAR;
433 }
431 return cast_int(var->k); 434 return cast_int(var->k);
432 } 435 }
433 } 436 }
@@ -467,8 +470,13 @@ static void marktobeclosed (FuncState *fs) {
467static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { 470static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
468 int v = searchvar(fs, n, var); /* look up variables at current level */ 471 int v = searchvar(fs, n, var); /* look up variables at current level */
469 if (v >= 0) { /* found? */ 472 if (v >= 0) { /* found? */
470 if (v == VLOCAL && !base) 473 if (!base) {
471 markupval(fs, var->u.var.vidx); /* local will be used as an upval */ 474 if (var->k == VVARGVAR) /* vararg parameter? */
475 luaK_vapar2local(fs, var); /* change it to a regular local */
476 if (var->k == VLOCAL)
477 markupval(fs, var->u.var.vidx); /* will be used as an upvalue */
478 }
479 /* else nothing else to be done */
472 } 480 }
473 else { /* not found at current level; try upvalues */ 481 else { /* not found at current level; try upvalues */
474 int idx = searchupvalue(fs, n); /* try existing upvalues */ 482 int idx = searchupvalue(fs, n); /* try existing upvalues */
@@ -1066,8 +1074,8 @@ static void parlist (LexState *ls) {
1066 varargk |= PF_ISVARARG; 1074 varargk |= PF_ISVARARG;
1067 luaX_next(ls); 1075 luaX_next(ls);
1068 if (testnext(ls, '=')) { 1076 if (testnext(ls, '=')) {
1069 new_varkind(ls, str_checkname(ls), RDKVATAB); 1077 new_varkind(ls, str_checkname(ls), RDKVAVAR);
1070 varargk |= PF_VATAB; 1078 varargk |= PF_VAVAR;
1071 } 1079 }
1072 break; 1080 break;
1073 } 1081 }
@@ -1079,10 +1087,10 @@ static void parlist (LexState *ls) {
1079 f->numparams = cast_byte(fs->nactvar); 1087 f->numparams = cast_byte(fs->nactvar);
1080 if (varargk != 0) { 1088 if (varargk != 0) {
1081 setvararg(fs, varargk); /* declared vararg */ 1089 setvararg(fs, varargk); /* declared vararg */
1082 if (varargk & PF_VATAB) 1090 if (varargk & PF_VAVAR)
1083 adjustlocalvars(ls, 1); /* vararg table */ 1091 adjustlocalvars(ls, 1); /* vararg parameter */
1084 } 1092 }
1085 /* reserve registers for parameters (and vararg variable, if present) */ 1093 /* reserve registers for parameters (plus vararg parameter, if present) */
1086 luaK_reserveregs(fs, fs->nactvar); 1094 luaK_reserveregs(fs, fs->nactvar);
1087} 1095}
1088 1096
diff --git a/lparser.h b/lparser.h
index e479905e..327170e3 100644
--- a/lparser.h
+++ b/lparser.h
@@ -37,6 +37,8 @@ typedef enum {
37 info = result register */ 37 info = result register */
38 VLOCAL, /* local variable; var.ridx = register index; 38 VLOCAL, /* local variable; var.ridx = register index;
39 var.vidx = relative index in 'actvar.arr' */ 39 var.vidx = relative index in 'actvar.arr' */
40 VVARGVAR, /* vararg parameter; var.ridx = register index;
41 var.vidx = relative index in 'actvar.arr' */
40 VGLOBAL, /* global variable; 42 VGLOBAL, /* global variable;
41 info = relative index in 'actvar.arr' (or -1 for 43 info = relative index in 'actvar.arr' (or -1 for
42 implicit declaration) */ 44 implicit declaration) */
@@ -97,7 +99,7 @@ typedef struct expdesc {
97/* kinds of variables */ 99/* kinds of variables */
98#define VDKREG 0 /* regular local */ 100#define VDKREG 0 /* regular local */
99#define RDKCONST 1 /* local constant */ 101#define RDKCONST 1 /* local constant */
100#define RDKVATAB 2 /* vararg table */ 102#define RDKVAVAR 2 /* vararg parameter */
101#define RDKTOCLOSE 3 /* to-be-closed */ 103#define RDKTOCLOSE 3 /* to-be-closed */
102#define RDKCTC 4 /* local compile-time constant */ 104#define RDKCTC 4 /* local compile-time constant */
103#define GDKREG 5 /* regular global */ 105#define GDKREG 5 /* regular global */
diff --git a/ltm.c b/ltm.c
index 619be59e..cc812e62 100644
--- a/ltm.c
+++ b/ltm.c
@@ -265,11 +265,11 @@ void luaT_adjustvarargs (lua_State *L, CallInfo *ci, const Proto *p) {
265 setobjs2s(L, L->top.p++, ci->func.p + i); 265 setobjs2s(L, L->top.p++, ci->func.p + i);
266 setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */ 266 setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */
267 } 267 }
268 if (p->flag & (PF_VAPTAB | PF_VATAB)) { /* is there a vararg table? */ 268 if (p->flag & PF_VAVAR) { /* is there a vararg parameter? */
269 if (p->flag & PF_VAPTAB) /* is vararg table fake? */ 269 if (p->flag & PF_VATAB) /* does it need a vararg table? */
270 setnilvalue(s2v(L->top.p)); /* initialize it */
271 else
272 createvarargtab(L, ci->func.p + nfixparams + 1, nextra); 270 createvarargtab(L, ci->func.p + nfixparams + 1, nextra);
271 else /* no table; set parameter to nil */
272 setnilvalue(s2v(L->top.p));
273 } 273 }
274 ci->func.p += totalargs + 1; 274 ci->func.p += totalargs + 1;
275 ci->top.p += totalargs + 1; 275 ci->top.p += totalargs + 1;
diff --git a/testes/vararg.lua b/testes/vararg.lua
index 4320684e..92f720cb 100644
--- a/testes/vararg.lua
+++ b/testes/vararg.lua
@@ -150,5 +150,31 @@ do
150 local a, b = g() 150 local a, b = g()
151 assert(a == nil and b == 2) 151 assert(a == nil and b == 2)
152end 152end
153
154
155do -- vararg parameter used in nested functions
156 local function foo (... = tab1)
157 return function (... = tab2)
158 return {tab1, tab2}
159 end
160 end
161 local f = foo(10, 20, 30)
162 local t = f("a", "b")
163 assert(t[1].n == 3 and t[1][1] == 10)
164 assert(t[2].n == 2 and t[2][1] == "a")
165end
166
167do -- vararg parameter is read-only
168 local st, msg = load("return function (... = t) t = 10 end")
169 assert(string.find(msg, "const variable 't'"))
170
171 local st, msg = load[[
172 local function foo (... = extra)
173 return function (...) extra = nil end
174 end
175 ]]
176 assert(string.find(msg, "const variable 'extra'"))
177end
178
153print('OK') 179print('OK')
154 180