Varag parameter is a new kind of variable
To allow some optimizations on its use.
This commit is contained in:
12
lcode.c
12
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>).
|
** 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);
|
const2exp(const2val(fs, e), e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case VVARGVAR: {
|
||||||
|
luaK_vapar2local(fs, e); /* turn it into a local variable */
|
||||||
|
} /* FALLTHROUGH */
|
||||||
case VLOCAL: { /* already in a register */
|
case VLOCAL: { /* already in a register */
|
||||||
int temp = e->u.var.ridx;
|
int temp = e->u.var.ridx;
|
||||||
e->u.info = temp; /* (can't do a direct assignment; values overlap) */
|
e->u.info = temp; /* (can't do a direct assignment; values overlap) */
|
||||||
|
|||||||
1
lcode.h
1
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_reserveregs (FuncState *fs, int n);
|
||||||
LUAI_FUNC void luaK_checkstack (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_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 void luaK_dischargevars (FuncState *fs, expdesc *e);
|
||||||
LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
|
LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
|
||||||
LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
|
LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
|
||||||
|
|||||||
@@ -584,8 +584,8 @@ typedef struct AbsLineInfo {
|
|||||||
** Flags in Prototypes
|
** Flags in Prototypes
|
||||||
*/
|
*/
|
||||||
#define PF_ISVARARG 1 /* function is vararg */
|
#define PF_ISVARARG 1 /* function is vararg */
|
||||||
#define PF_VATAB 2 /* function is vararg with table */
|
#define PF_VAVAR 2 /* function has vararg parameter */
|
||||||
#define PF_VAPTAB 4 /* function is vararg with pseudo-table */
|
#define PF_VATAB 4 /* function has vararg table */
|
||||||
#define PF_FIXED 8 /* prototype has parts in fixed memory */
|
#define PF_FIXED 8 /* prototype has parts in fixed memory */
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
26
lparser.c
26
lparser.c
@@ -289,7 +289,7 @@ static void check_readonly (LexState *ls, expdesc *e) {
|
|||||||
varname = ls->dyd->actvar.arr[e->u.info].vd.name;
|
varname = ls->dyd->actvar.arr[e->u.info].vd.name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VLOCAL: {
|
case VLOCAL: case VVARGVAR: {
|
||||||
Vardesc *vardesc = getlocalvardesc(fs, e->u.var.vidx);
|
Vardesc *vardesc = getlocalvardesc(fs, e->u.var.vidx);
|
||||||
if (vardesc->vd.kind != VDKREG) /* not a regular variable? */
|
if (vardesc->vd.kind != VDKREG) /* not a regular variable? */
|
||||||
varname = vardesc->vd.name;
|
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? */
|
else if (eqstr(n, vd->vd.name)) { /* found? */
|
||||||
if (vd->vd.kind == RDKCTC) /* compile-time constant? */
|
if (vd->vd.kind == RDKCTC) /* compile-time constant? */
|
||||||
init_exp(var, VCONST, fs->firstlocal + i);
|
init_exp(var, VCONST, fs->firstlocal + i);
|
||||||
else /* local variable */
|
else { /* local variable */
|
||||||
init_var(fs, var, i);
|
init_var(fs, var, i);
|
||||||
|
if (vd->vd.kind == RDKVAVAR) /* vararg parameter? */
|
||||||
|
var->k = VVARGVAR;
|
||||||
|
}
|
||||||
return cast_int(var->k);
|
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) {
|
static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
|
||||||
int v = searchvar(fs, n, var); /* look up variables at current level */
|
int v = searchvar(fs, n, var); /* look up variables at current level */
|
||||||
if (v >= 0) { /* found? */
|
if (v >= 0) { /* found? */
|
||||||
if (v == VLOCAL && !base)
|
if (!base) {
|
||||||
markupval(fs, var->u.var.vidx); /* local will be used as an upval */
|
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 */
|
else { /* not found at current level; try upvalues */
|
||||||
int idx = searchupvalue(fs, n); /* try existing upvalues */
|
int idx = searchupvalue(fs, n); /* try existing upvalues */
|
||||||
@@ -1066,8 +1074,8 @@ static void parlist (LexState *ls) {
|
|||||||
varargk |= PF_ISVARARG;
|
varargk |= PF_ISVARARG;
|
||||||
luaX_next(ls);
|
luaX_next(ls);
|
||||||
if (testnext(ls, '=')) {
|
if (testnext(ls, '=')) {
|
||||||
new_varkind(ls, str_checkname(ls), RDKVATAB);
|
new_varkind(ls, str_checkname(ls), RDKVAVAR);
|
||||||
varargk |= PF_VATAB;
|
varargk |= PF_VAVAR;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1079,10 +1087,10 @@ static void parlist (LexState *ls) {
|
|||||||
f->numparams = cast_byte(fs->nactvar);
|
f->numparams = cast_byte(fs->nactvar);
|
||||||
if (varargk != 0) {
|
if (varargk != 0) {
|
||||||
setvararg(fs, varargk); /* declared vararg */
|
setvararg(fs, varargk); /* declared vararg */
|
||||||
if (varargk & PF_VATAB)
|
if (varargk & PF_VAVAR)
|
||||||
adjustlocalvars(ls, 1); /* vararg table */
|
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);
|
luaK_reserveregs(fs, fs->nactvar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ typedef enum {
|
|||||||
info = result register */
|
info = result register */
|
||||||
VLOCAL, /* local variable; var.ridx = register index;
|
VLOCAL, /* local variable; var.ridx = register index;
|
||||||
var.vidx = relative index in 'actvar.arr' */
|
var.vidx = relative index in 'actvar.arr' */
|
||||||
|
VVARGVAR, /* vararg parameter; var.ridx = register index;
|
||||||
|
var.vidx = relative index in 'actvar.arr' */
|
||||||
VGLOBAL, /* global variable;
|
VGLOBAL, /* global variable;
|
||||||
info = relative index in 'actvar.arr' (or -1 for
|
info = relative index in 'actvar.arr' (or -1 for
|
||||||
implicit declaration) */
|
implicit declaration) */
|
||||||
@@ -97,7 +99,7 @@ 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 RDKVATAB 2 /* vararg table */
|
#define RDKVAVAR 2 /* vararg parameter */
|
||||||
#define RDKTOCLOSE 3 /* to-be-closed */
|
#define RDKTOCLOSE 3 /* to-be-closed */
|
||||||
#define RDKCTC 4 /* local compile-time constant */
|
#define RDKCTC 4 /* local compile-time constant */
|
||||||
#define GDKREG 5 /* regular global */
|
#define GDKREG 5 /* regular global */
|
||||||
|
|||||||
8
ltm.c
8
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);
|
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) */
|
||||||
}
|
}
|
||||||
if (p->flag & (PF_VAPTAB | PF_VATAB)) { /* is there a vararg table? */
|
if (p->flag & PF_VAVAR) { /* is there a vararg parameter? */
|
||||||
if (p->flag & PF_VAPTAB) /* is vararg table fake? */
|
if (p->flag & PF_VATAB) /* does it need a vararg table? */
|
||||||
setnilvalue(s2v(L->top.p)); /* initialize it */
|
|
||||||
else
|
|
||||||
createvarargtab(L, ci->func.p + nfixparams + 1, nextra);
|
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->func.p += totalargs + 1;
|
||||||
ci->top.p += totalargs + 1;
|
ci->top.p += totalargs + 1;
|
||||||
|
|||||||
@@ -150,5 +150,31 @@ do
|
|||||||
local a, b = g()
|
local a, b = g()
|
||||||
assert(a == nil and b == 2)
|
assert(a == nil and b == 2)
|
||||||
end
|
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')
|
print('OK')
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user