mirror of
https://github.com/lua/lua.git
synced 2026-01-26 07:37:58 +00:00
Functions with vararg tables don't need hidden args.
Vararg functions with vararg tables don't use the arguments hidden in the stack; therfore, it doesn't need to build/keep them.
This commit is contained in:
parent
f33cc4ddec
commit
a07f6a8241
12
lcode.c
12
lcode.c
@ -806,7 +806,7 @@ 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 */
|
||||
needvatab(fs->f); /* function will need a vararg table */
|
||||
/* now a vararg parameter is equivalent to a regular local variable */
|
||||
var->k = VLOCAL;
|
||||
}
|
||||
@ -1127,7 +1127,7 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
|
||||
break;
|
||||
}
|
||||
case VVARGIND: {
|
||||
fs->f->flag |= PF_VATAB; /* function will need a vararg table */
|
||||
needvatab(fs->f); /* function will need a vararg table */
|
||||
/* now, assignment is to a regular table */
|
||||
} /* FALLTHROUGH */
|
||||
case VINDEXED: {
|
||||
@ -1927,6 +1927,8 @@ static int finaltarget (Instruction *code, int i) {
|
||||
void luaK_finish (FuncState *fs) {
|
||||
int i;
|
||||
Proto *p = fs->f;
|
||||
if (p->flag & PF_VATAB) /* will it use a vararg table? */
|
||||
p->flag &= cast_byte(~PF_VAHID); /* then it will not use hidden args. */
|
||||
for (i = 0; i < fs->pc; i++) {
|
||||
Instruction *pc = &p->code[i];
|
||||
/* avoid "not used" warnings when assert is off (for 'onelua.c') */
|
||||
@ -1934,7 +1936,7 @@ void luaK_finish (FuncState *fs) {
|
||||
lua_assert(i == 0 || luaP_isOT(*(pc - 1)) == luaP_isIT(*pc));
|
||||
switch (GET_OPCODE(*pc)) {
|
||||
case OP_RETURN0: case OP_RETURN1: {
|
||||
if (!(fs->needclose || (p->flag & PF_ISVARARG)))
|
||||
if (!(fs->needclose || (p->flag & PF_VAHID)))
|
||||
break; /* no extra work */
|
||||
/* else use OP_RETURN to do the extra work */
|
||||
SET_OPCODE(*pc, OP_RETURN);
|
||||
@ -1942,8 +1944,8 @@ void luaK_finish (FuncState *fs) {
|
||||
case OP_RETURN: case OP_TAILCALL: {
|
||||
if (fs->needclose)
|
||||
SETARG_k(*pc, 1); /* signal that it needs to close */
|
||||
if (p->flag & PF_ISVARARG)
|
||||
SETARG_C(*pc, p->numparams + 1); /* signal that it is vararg */
|
||||
if (p->flag & PF_VAHID) /* does it use hidden arguments? */
|
||||
SETARG_C(*pc, p->numparams + 1); /* signal that */
|
||||
break;
|
||||
}
|
||||
case OP_GETVARG: {
|
||||
|
||||
8
ldebug.c
8
ldebug.c
@ -184,7 +184,7 @@ static const char *upvalname (const Proto *p, int uv) {
|
||||
|
||||
|
||||
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
|
||||
if (clLvalue(s2v(ci->func.p))->p->flag & PF_ISVARARG) {
|
||||
if (clLvalue(s2v(ci->func.p))->p->flag & PF_VAHID) {
|
||||
int nextra = ci->u.l.nextraargs;
|
||||
if (n >= -nextra) { /* 'n' is negative */
|
||||
*pos = ci->func.p - nextra - (n + 1);
|
||||
@ -304,7 +304,7 @@ static void collectvalidlines (lua_State *L, Closure *f) {
|
||||
int i;
|
||||
TValue v;
|
||||
setbtvalue(&v); /* boolean 'true' to be the value of all indices */
|
||||
if (!(p->flag & PF_ISVARARG)) /* regular function? */
|
||||
if (!(isvararg(p))) /* regular function? */
|
||||
i = 0; /* consider all instructions */
|
||||
else { /* vararg function */
|
||||
lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP);
|
||||
@ -348,7 +348,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
|
||||
ar->nparams = 0;
|
||||
}
|
||||
else {
|
||||
ar->isvararg = (f->l.p->flag & PF_ISVARARG) ? 1 : 0;
|
||||
ar->isvararg = (isvararg(f->l.p)) ? 1 : 0;
|
||||
ar->nparams = f->l.p->numparams;
|
||||
}
|
||||
break;
|
||||
@ -912,7 +912,7 @@ int luaG_tracecall (lua_State *L) {
|
||||
Proto *p = ci_func(ci)->p;
|
||||
ci->u.l.trap = 1; /* ensure hooks will be checked */
|
||||
if (ci->u.l.savedpc == p->code) { /* first instruction (not resuming)? */
|
||||
if (p->flag & PF_ISVARARG)
|
||||
if (isvararg(p))
|
||||
return 0; /* hooks will start at VARARGPREP instruction */
|
||||
else if (!(ci->callstatus & CIST_HOOKYIELD)) /* not yielded? */
|
||||
luaD_hookcall(L, ci); /* check 'call' hook */
|
||||
|
||||
2
ldo.c
2
ldo.c
@ -487,7 +487,7 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
|
||||
int ftransfer;
|
||||
if (isLua(ci)) {
|
||||
Proto *p = ci_func(ci)->p;
|
||||
if (p->flag & PF_ISVARARG)
|
||||
if (p->flag & PF_VAHID)
|
||||
delta = ci->u.l.nextraargs + p->numparams + 1;
|
||||
}
|
||||
ci->func.p += delta; /* if vararg, back to virtual 'func' */
|
||||
|
||||
10
lobject.h
10
lobject.h
@ -583,10 +583,18 @@ typedef struct AbsLineInfo {
|
||||
/*
|
||||
** Flags in Prototypes
|
||||
*/
|
||||
#define PF_ISVARARG 1 /* function is vararg */
|
||||
#define PF_VAHID 1 /* function has hidden vararg arguments */
|
||||
#define PF_VATAB 2 /* function has vararg table */
|
||||
#define PF_FIXED 4 /* prototype has parts in fixed memory */
|
||||
|
||||
/* a vararg function either has hidden args. or a vararg table */
|
||||
#define isvararg(p) ((p)->flag & (PF_VAHID | PF_VATAB))
|
||||
|
||||
/*
|
||||
** mark that a function needs a vararg table. (The flag PF_VAHID will
|
||||
** be cleared later.)
|
||||
*/
|
||||
#define needvatab(p) ((p)->flag |= PF_VATAB)
|
||||
|
||||
/*
|
||||
** Function Prototypes
|
||||
|
||||
31
lopcodes.h
31
lopcodes.h
@ -224,8 +224,8 @@ enum OpMode {iABC, ivABC, iABx, iAsBx, iAx, isJ};
|
||||
|
||||
|
||||
/*
|
||||
** Grep "ORDER OP" if you change these enums. Opcodes marked with a (*)
|
||||
** has extra descriptions in the notes after the enumeration.
|
||||
** Grep "ORDER OP" if you change this enum.
|
||||
** See "Notes" below for more information about some instructions.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
@ -238,7 +238,7 @@ OP_LOADF,/* A sBx R[A] := (lua_Number)sBx */
|
||||
OP_LOADK,/* A Bx R[A] := K[Bx] */
|
||||
OP_LOADKX,/* A R[A] := K[extra arg] */
|
||||
OP_LOADFALSE,/* A R[A] := false */
|
||||
OP_LFALSESKIP,/*A R[A] := false; pc++ (*) */
|
||||
OP_LFALSESKIP,/*A R[A] := false; pc++ */
|
||||
OP_LOADTRUE,/* A R[A] := true */
|
||||
OP_LOADNIL,/* A B R[A], R[A+1], ..., R[A+B] := nil */
|
||||
OP_GETUPVAL,/* A B R[A] := UpValue[B] */
|
||||
@ -289,7 +289,7 @@ OP_BXOR,/* A B C R[A] := R[B] ~ R[C] */
|
||||
OP_SHL,/* A B C R[A] := R[B] << R[C] */
|
||||
OP_SHR,/* A B C R[A] := R[B] >> R[C] */
|
||||
|
||||
OP_MMBIN,/* A B C call C metamethod over R[A] and R[B] (*) */
|
||||
OP_MMBIN,/* A B C call C metamethod over R[A] and R[B] */
|
||||
OP_MMBINI,/* A sB C k call C metamethod over R[A] and sB */
|
||||
OP_MMBINK,/* A B C k call C metamethod over R[A] and K[B] */
|
||||
|
||||
@ -315,12 +315,12 @@ OP_GTI,/* A sB k if ((R[A] > sB) ~= k) then pc++ */
|
||||
OP_GEI,/* A sB k if ((R[A] >= sB) ~= k) then pc++ */
|
||||
|
||||
OP_TEST,/* A k if (not R[A] == k) then pc++ */
|
||||
OP_TESTSET,/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] (*) */
|
||||
OP_TESTSET,/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] */
|
||||
|
||||
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 k return R[A](R[A+1], ... ,R[A+B-1]) */
|
||||
|
||||
OP_RETURN,/* A B C k return R[A], ... ,R[A+B-2] (see note) */
|
||||
OP_RETURN,/* A B C k return R[A], ... ,R[A+B-2] */
|
||||
OP_RETURN0,/* return */
|
||||
OP_RETURN1,/* A return R[A] */
|
||||
|
||||
@ -336,13 +336,13 @@ OP_SETLIST,/* A vB vC k R[A][vC+i] := R[A+i], 1 <= i <= vB */
|
||||
|
||||
OP_CLOSURE,/* A Bx R[A] := closure(KPROTO[Bx]) */
|
||||
|
||||
OP_VARARG,/* A C R[A], ..., R[A+C-2] = vararg, R[B] is vararg param. */
|
||||
OP_VARARG,/* A B C k R[A], ..., R[A+C-2] = varargs */
|
||||
|
||||
OP_GETVARG, /* A B C R[A] := R[B][R[C]], R[B] is vararg parameter */
|
||||
|
||||
OP_ERRNNIL,/* A Bx raise error if R[A] ~= nil (K[Bx - 1] is global name)*/
|
||||
|
||||
OP_VARARGPREP,/* (adjust vararg parameters) */
|
||||
OP_VARARGPREP,/* (adjust varargs) */
|
||||
|
||||
OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
|
||||
} OpCode;
|
||||
@ -371,7 +371,8 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
|
||||
OP_RETURN*, 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).
|
||||
set top (like in OP_CALL with C == 0). 'k' means function has a
|
||||
vararg table, which is in R[B].
|
||||
|
||||
(*) In OP_RETURN, if (B == 0) then return up to 'top'.
|
||||
|
||||
@ -387,20 +388,22 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
|
||||
is vC. Otherwise, the array size is EXTRAARG _ vC.
|
||||
|
||||
(*) In OP_ERRNNIL, (Bx == 0) means index of global name doesn't
|
||||
fit in Bx. (So, that name is not available for the instruction.)
|
||||
fit in Bx. (So, that name is not available for the error message.)
|
||||
|
||||
(*) For comparisons, k specifies what condition the test should accept
|
||||
(true or false).
|
||||
|
||||
(*) In OP_MMBINI/OP_MMBINK, k means the arguments were flipped
|
||||
(the constant is the first operand).
|
||||
(the constant is the first operand).
|
||||
|
||||
(*) All 'skips' (pc++) assume that next instruction is a jump.
|
||||
(*) All comparison and test instructions assume that the instruction
|
||||
being skipped (pc++) is a jump.
|
||||
|
||||
(*) In instructions OP_RETURN/OP_TAILCALL, 'k' specifies that the
|
||||
function builds upvalues, which may need to be closed. C > 0 means
|
||||
the function is vararg, so that its 'func' must be corrected before
|
||||
returning; in this case, (C - 1) is its number of fixed parameters.
|
||||
the function has hidden vararg arguments, so that its 'func' must be
|
||||
corrected before returning; in this case, (C - 1) is its number of
|
||||
fixed parameters.
|
||||
|
||||
(*) In comparisons with an immediate operand, C signals whether the
|
||||
original operand was a float. (It must be corrected in case of
|
||||
|
||||
@ -304,7 +304,7 @@ static void check_readonly (LexState *ls, expdesc *e) {
|
||||
break;
|
||||
}
|
||||
case VVARGIND: {
|
||||
fs->f->flag |= PF_VATAB; /* function will need a vararg table */
|
||||
needvatab(fs->f); /* function will need a vararg table */
|
||||
e->k = VINDEXED;
|
||||
} /* FALLTHROUGH */
|
||||
case VINDEXUP: case VINDEXSTR: case VINDEXED: { /* global variable */
|
||||
@ -1057,7 +1057,7 @@ static void constructor (LexState *ls, expdesc *t) {
|
||||
|
||||
|
||||
static void setvararg (FuncState *fs) {
|
||||
fs->f->flag |= PF_ISVARARG;
|
||||
fs->f->flag |= PF_VAHID; /* by default, use hidden vararg arguments */
|
||||
luaK_codeABC(fs, OP_VARARGPREP, 0, 0, 0);
|
||||
}
|
||||
|
||||
@ -1283,7 +1283,7 @@ static void simpleexp (LexState *ls, expdesc *v) {
|
||||
}
|
||||
case TK_DOTS: { /* vararg */
|
||||
FuncState *fs = ls->fs;
|
||||
check_condition(ls, fs->f->flag & PF_ISVARARG,
|
||||
check_condition(ls, isvararg(fs->f),
|
||||
"cannot use '...' outside a vararg function");
|
||||
init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, fs->f->numparams, 1));
|
||||
break;
|
||||
|
||||
41
ltm.c
41
ltm.c
@ -250,31 +250,42 @@ static void createvarargtab (lua_State *L, StkId f, int n) {
|
||||
** initial stack: func arg1 ... argn extra1 ...
|
||||
** ^ ci->func ^ L->top
|
||||
** final stack: func nil ... nil extra1 ... func arg1 ... argn
|
||||
** ^ ci->func ^ L->top
|
||||
** ^ ci->func
|
||||
*/
|
||||
void luaT_adjustvarargs (lua_State *L, CallInfo *ci, const Proto *p) {
|
||||
static void buildhiddenargs (lua_State *L, CallInfo *ci, const Proto *p,
|
||||
int totalargs, int nfixparams, int nextra) {
|
||||
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;
|
||||
luaD_checkstack(L, p->maxstacksize + 1);
|
||||
/* copy function to the top of the stack */
|
||||
/* copy function to the top of the stack, after extra arguments */
|
||||
setobjs2s(L, L->top.p++, ci->func.p);
|
||||
/* move fixed parameters to the top of the stack */
|
||||
/* move fixed parameters to after the copied function */
|
||||
for (i = 1; i <= nfixparams; i++) {
|
||||
setobjs2s(L, L->top.p++, ci->func.p + i);
|
||||
setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */
|
||||
}
|
||||
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));
|
||||
L->top.p++;
|
||||
}
|
||||
ci->func.p += totalargs + 1;
|
||||
ci->func.p += totalargs + 1; /* 'func' now lives after hidden arguments */
|
||||
ci->top.p += totalargs + 1;
|
||||
lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
|
||||
}
|
||||
|
||||
|
||||
void luaT_adjustvarargs (lua_State *L, CallInfo *ci, const Proto *p) {
|
||||
int totalargs = cast_int(L->top.p - ci->func.p) - 1;
|
||||
int nfixparams = p->numparams;
|
||||
int nextra = totalargs - nfixparams; /* number of extra arguments */
|
||||
if (p->flag & PF_VATAB) { /* does it need a vararg table? */
|
||||
lua_assert(!(p->flag & PF_VAHID));
|
||||
createvarargtab(L, ci->func.p + nfixparams + 1, nextra);
|
||||
/* move table to proper place (last parameter) */
|
||||
setobjs2s(L, ci->func.p + nfixparams + 1, L->top.p - 1);
|
||||
}
|
||||
else { /* no table */
|
||||
lua_assert(p->flag & PF_VAHID);
|
||||
buildhiddenargs(L, ci, p, totalargs, nfixparams, nextra);
|
||||
/* set vararg parameter to nil */
|
||||
setnilvalue(s2v(ci->func.p + nfixparams + 1));
|
||||
lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -2425,7 +2425,7 @@ The conditions are as follows:
|
||||
If the vararg table has a name,
|
||||
that name is not an upvalue in a nested function
|
||||
and it is used only as the base table
|
||||
in the syntactic constructions @T{t[exp]} or @T{t.id}).
|
||||
in the syntactic constructions @T{t[exp]} or @T{t.id}.
|
||||
Note that an anonymous vararg table always satisfy these conditions.
|
||||
|
||||
}
|
||||
|
||||
@ -726,6 +726,9 @@ assert(t.isvararg == false and t.nparams == 3 and t.nups == 0)
|
||||
t = debug.getinfo(function (a,b,...) return t[a] end, "u")
|
||||
assert(t.isvararg == true and t.nparams == 2 and t.nups == 1)
|
||||
|
||||
t = debug.getinfo(function (a,b,...t) t.n = 2; return t[a] end, "u")
|
||||
assert(t.isvararg == true and t.nparams == 2 and t.nups == 0)
|
||||
|
||||
t = debug.getinfo(1) -- main
|
||||
assert(t.isvararg == true and t.nparams == 0 and t.nups == 1 and
|
||||
debug.getupvalue(t.func, 1) == "_ENV")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user