diffu-lua-5.5.0-rc1-rc2
README
@@ -1,5 +1,5 @@
-This is Lua 5.5.0, released on 14 Nov 2025.
+This is Lua 5.5.0, released on 01 Dec 2025.
For installation instructions, license details, and
further information about Lua, see doc/readme.html.
doc/contents.html
@@ -85,7 +85,8 @@
<LI><A HREF="manual.html#3.4.9">3.4.9 – Table Constructors</A>
<LI><A HREF="manual.html#3.4.10">3.4.10 – Function Calls</A>
<LI><A HREF="manual.html#3.4.11">3.4.11 – Function Definitions</A>
-<LI><A HREF="manual.html#3.4.12">3.4.12 – Lists of expressions, multiple results, and adjustment<A>
+<LI><A HREF="manual.html#3.4.12">3.4.12 – Lists of Expressions, Multiple Results, and Adjustment</A>
+</UL>
</UL>
<P>
<LI><A HREF="manual.html#4">4 – The Application Program Interface</A>
@@ -94,7 +95,7 @@
<UL>
<LI><A HREF="manual.html#4.1.1">4.1.1 – Stack Size</A>
<LI><A HREF="manual.html#4.1.2">4.1.2 – Valid and Acceptable Indices</A>
-<LI><A HREF="manual.html#4.1.3">4.1.3 – Pointers to strings</A>
+<LI><A HREF="manual.html#4.1.3">4.1.3 – Pointers to Strings</A>
</UL>
<LI><A HREF="manual.html#4.2">4.2 – C Closures</A>
<LI><A HREF="manual.html#4.3">4.3 – Registry</A>
@@ -674,7 +675,7 @@
<P CLASS="footer">
Last update:
-Sat Nov 15 00:51:05 UTC 2025
+Mon Dec 1 13:57:23 UTC 2025
</P>
<!--
Last change: revised for Lua 5.5.0
doc/manual.html
@@ -2701,7 +2701,7 @@
</pre><p>
can be used to emulate methods.
A call <code>v:name(<em>args</em>)</code>
-is syntactic sugar for <code>v.name(v,<em>args</em>)</code>,
+is syntactic sugar for <code>v.name(v, <em>args</em>)</code>,
except that <code>v</code> is evaluated only once.
@@ -2885,14 +2885,10 @@
at the end of its parameter list.
A variadic function does not adjust its argument list;
instead, it collects all extra arguments and supplies them
-to the function through a <em>vararg expression</em> and,
-if present, a <em>vararg table</em>.
-
-
-<p>
-A vararg expression is also written as three dots,
-and its value is a list of all actual extra arguments,
-similar to a function with multiple results (see <a href="#3.4.12">§3.4.12</a>).
+to the function through a <em>vararg table</em>.
+In that table,
+the values at indices 1, 2, etc. are the extra arguments,
+and the value at index "<code>n</code>" is the number of extra arguments.
<p>
@@ -2904,7 +2900,7 @@
function r() return 1,2,3 end
</pre><p>
Then, we have the following mapping from arguments to parameters and
-to the vararg expression:
+to the vararg table:
<pre>
CALL PARAMETERS
@@ -2915,35 +2911,44 @@
f(r(), 10) a=1, b=10
f(r()) a=1, b=2
- g(3) a=3, b=nil, ... -> (nothing)
- g(3, 4) a=3, b=4, ... -> (nothing)
- g(3, 4, 5, 8) a=3, b=4, ... -> 5 8
- g(5, r()) a=5, b=1, ... -> 2 3
+ g(3) a=3, b=nil, va. table -> {n = 0}
+ g(3, 4) a=3, b=4, va. table -> {n = 0}
+ g(3, 4, 5, 8) a=3, b=4, va. table -> {5, 8, n = 2}
+ g(5, r()) a=5, b=1, va. table -> {2, 3, n = 2}
</pre>
<p>
-The presence of a varag table in a variadic function is indicated
-by a name after the three dots.
+A vararg table in a variadic function can have an optional name,
+given after the three dots.
When present,
-a vararg table behaves like a read-only local variable
-with the given name that is initialized with a table.
-In that table,
-the values at indices 1, 2, etc. are the extra arguments,
-and the value at index "<code>n</code>" is the number of extra arguments.
-In other words, the code behaves as if the function started with
-the following statement,
-assuming the standard behavior of <a href="#pdf-table.pack"><code>table.pack</code></a>:
+that name denotes a read-only local variable that
+refers to the vararg table.
+If the vararg table does not have a name,
+it can only be accessed through a vararg expression.
+
+
+<p>
+A vararg expression is also written as three dots,
+and its value is a list of the values in the vararg table,
+from 1 to the integer value at index "<code>n</code>".
+(Therefore, if the code does not modify the vararg table,
+this list corresponds to the extra arguments in the function call.)
+This list behaves like the results from a
+function with multiple results (see <a href="#3.4.12">§3.4.12</a>).
-<pre>
- local <const> name = table.pack(...)
-</pre>
<p>
As an optimization,
-if the vararg table is used only as a base in indexing expressions
-(the <code>t</code> in <code>t[exp]</code> or <code>t.id</code>) and it is not an upvalue,
+if the vararg table satisfies some conditions,
the code does not create an actual table and instead translates
-the indexing expressions into accesses to the internal vararg data.
+the indexing expressions and the vararg expressions
+into accesses to the internal vararg data.
+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 <code>t[exp]</code> or <code>t.id</code>).
+Note that an anonymous vararg table always satisfy these conditions.
@@ -2951,8 +2956,7 @@
-<h3>3.4.12 – <a name="3.4.12">Lists of expressions, multiple results,
-and adjustment</a></h3>
+<h3>3.4.12 – <a name="3.4.12">Lists of Expressions, Multiple Results, and Adjustment</a></h3>
<p>
Both function calls and vararg expressions can result in multiple values.
@@ -3256,7 +3260,7 @@
-<h3>4.1.3 – <a name="4.1.3">Pointers to strings</a></h3>
+<h3>4.1.3 – <a name="4.1.3">Pointers to Strings</a></h3>
<p>
Several functions in the API return pointers (<code>const char*</code>)
@@ -3751,7 +3755,7 @@
</pre><p>
Note that ISO C ensures
that <code>free(NULL)</code> has no effect and that
-<code>realloc(NULL,size)</code> is equivalent to <code>malloc(size)</code>.
+<code>realloc(NULL, size)</code> is equivalent to <code>malloc(size)</code>.
@@ -5113,6 +5117,10 @@
Lua will call <code>falloc</code> before raising the error.
+<p>
+The function returns a pointer to the string (that is, <code>s</code>).
+
+
@@ -10726,7 +10734,7 @@
<p>
-<hr><h3><a name="pdf-math.ldexp"><code>math.ldexp(m, e)</code></a></h3>
+<hr><h3><a name="pdf-math.ldexp"><code>math.ldexp (m, e)</code></a></h3>
<p>
@@ -11794,6 +11802,12 @@
if they were optimized away by the compiler.
Negative indices refer to vararg arguments;
-1 is the first vararg argument.
+These negative indices are only available when the vararg table
+has been optimized away;
+otherwise, the vararg arguments are available in the vararg table.
+
+
+<p>
The function returns <b>fail</b>
if there is no variable with the given index,
and raises an error when called with a level out of range.
@@ -12485,7 +12499,7 @@
<P CLASS="footer">
Last update:
-Sat Nov 15 00:41:28 UTC 2025
+Mon Dec 1 13:38:36 UTC 2025
</P>
<!--
Last change: revised for Lua 5.5.0
src/lcode.c
@@ -806,7 +806,7 @@
** 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 @@
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 @@
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 @@
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 @@
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: {
@@ -1951,6 +1953,11 @@
SET_OPCODE(*pc, OP_GETTABLE); /* must get vararg there */
break;
}
+ case OP_VARARG: {
+ if (p->flag & PF_VATAB) /* function has a vararg table? */
+ SETARG_k(*pc, 1); /* must get vararg there */
+ break;
+ }
case OP_JMP: { /* to optimize jumps to jumps */
int target = finaltarget(p->code, i);
fixjump(fs, i, target); /* jump directly to final target */
src/lcorolib.c
@@ -189,15 +189,17 @@
return 2;
}
}
- case COS_RUN: /* running coroutine? */
+ case COS_NORM:
+ return luaL_error(L, "cannot close a %s coroutine", statname[status]);
+ case COS_RUN:
lua_geti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD); /* get main */
if (lua_tothread(L, -1) == co)
return luaL_error(L, "cannot close main thread");
lua_closethread(co, L); /* close itself */
- lua_assert(0); /* previous call does not return */
+ /* previous call does not return *//* FALLTHROUGH */
+ default:
+ lua_assert(0);
return 0;
- default: /* normal or running coroutine */
- return luaL_error(L, "cannot close a %s coroutine", statname[status]);
}
}
src/ldebug.c
@@ -184,7 +184,7 @@
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 @@
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 @@
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 @@
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 */
src/ldo.c
@@ -487,7 +487,7 @@
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' */
src/lobject.h
@@ -583,11 +583,18 @@
/*
** Flags in Prototypes
*/
-#define PF_ISVARARG 1 /* function is vararg */
-#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 */
+#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
src/lopcodes.h
@@ -224,8 +224,8 @@
/*
-** 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_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_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_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_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 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] is global name)*/
+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_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'.
@@ -386,18 +387,23 @@
power of 2) plus 1, or zero for size zero. If not k, the array size
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 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
src/lparser.c
@@ -304,7 +304,7 @@
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 */
@@ -1056,9 +1056,8 @@
/* }====================================================================== */
-static void setvararg (FuncState *fs, int kind) {
- lua_assert(kind & PF_ISVARARG);
- fs->f->flag |= cast_byte(kind);
+static void setvararg (FuncState *fs) {
+ fs->f->flag |= PF_VAHID; /* by default, use hidden vararg arguments */
luaK_codeABC(fs, OP_VARARGPREP, 0, 0, 0);
}
@@ -1078,12 +1077,12 @@
break;
}
case TK_DOTS: {
- varargk |= PF_ISVARARG;
+ varargk = 1;
luaX_next(ls); /* skip '...' */
- if (ls->t.token == TK_NAME) {
+ if (ls->t.token == TK_NAME)
new_varkind(ls, str_checkname(ls), RDKVAVAR);
- varargk |= PF_VAVAR;
- }
+ else
+ new_localvarliteral(ls, "(vararg table)");
break;
}
default: luaX_syntaxerror(ls, "<name> or '...' expected");
@@ -1092,10 +1091,9 @@
}
adjustlocalvars(ls, nparams);
f->numparams = cast_byte(fs->nactvar);
- if (varargk != 0) {
- setvararg(fs, varargk); /* declared vararg */
- if (varargk & PF_VAVAR)
- adjustlocalvars(ls, 1); /* vararg parameter */
+ if (varargk) {
+ setvararg(fs); /* declared vararg */
+ adjustlocalvars(ls, 1); /* vararg parameter */
}
/* reserve registers for parameters (plus vararg parameter, if present) */
luaK_reserveregs(fs, fs->nactvar);
@@ -1285,9 +1283,9 @@
}
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, 0, 1));
+ init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, fs->f->numparams, 1));
break;
}
case '{' /*}*/: { /* constructor */
@@ -2153,7 +2151,7 @@
BlockCnt bl;
Upvaldesc *env;
open_func(ls, fs, &bl);
- setvararg(fs, PF_ISVARARG); /* main function is always vararg */
+ setvararg(fs); /* main function is always vararg */
env = allocupvalue(fs); /* ...set environment upvalue */
env->instack = 1;
env->idx = 0;
src/ltm.c
@@ -242,6 +242,7 @@
luaH_set(L, t, &key, &value); /* t.n = n */
for (i = 0; i < n; i++)
luaH_setint(L, t, i + 1, s2v(f + i));
+ luaC_checkGC(L);
}
@@ -249,31 +250,42 @@
** 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_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->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);
+ }
}
@@ -299,16 +311,53 @@
}
-void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
- int i;
- int nextra = ci->u.l.nextraargs;
+/*
+** Get the number of extra arguments in a vararg function. If vararg
+** table has been optimized away, that number is in the call info.
+** Otherwise, get the field 'n' from the vararg table and check that it
+** has a proper value (non-negative integer not larger than the stack
+** limit).
+*/
+static int getnumargs (lua_State *L, CallInfo *ci, Table *h) {
+ if (h == NULL) /* no vararg table? */
+ return ci->u.l.nextraargs;
+ else {
+ TValue res;
+ if (luaH_getshortstr(h, luaS_new(L, "n"), &res) != LUA_VNUMINT ||
+ l_castS2U(ivalue(&res)) > cast_uint(INT_MAX/2))
+ luaG_runerror(L, "vararg table has no proper 'n'");
+ return cast_int(ivalue(&res));
+ }
+}
+
+
+/*
+** Get 'wanted' vararg arguments and put them in 'where'. 'vatab' is
+** the register of the vararg table or -1 if there is no vararg table.
+*/
+void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted,
+ int vatab) {
+ Table *h = (vatab < 0) ? NULL : hvalue(s2v(ci->func.p + vatab + 1));
+ int nargs = getnumargs(L, ci, h); /* number of available vararg args. */
+ int i, touse; /* 'touse' is minimum between 'wanted' and 'nargs' */
if (wanted < 0) {
- wanted = nextra; /* get all extra arguments available */
- checkstackp(L, nextra, where); /* ensure stack space */
- L->top.p = where + nextra; /* next instruction will need top */
+ touse = wanted = nargs; /* get all extra arguments available */
+ checkstackp(L, nargs, where); /* ensure stack space */
+ L->top.p = where + nargs; /* next instruction will need top */
+ }
+ else
+ touse = (nargs > wanted) ? wanted : nargs;
+ if (h == NULL) { /* no vararg table? */
+ for (i = 0; i < touse; i++) /* get vararg values from the stack */
+ setobjs2s(L, where + i, ci->func.p - nargs + i);
+ }
+ else { /* get vararg values from vararg table */
+ for (i = 0; i < touse; i++) {
+ lu_byte tag = luaH_getint(h, i + 1, s2v(where + i));
+ if (tagisempty(tag))
+ setnilvalue(s2v(where + i));
+ }
}
- for (i = 0; i < wanted && i < nextra; i++)
- setobjs2s(L, where + i, ci->func.p - nextra + i);
for (; i < wanted; i++) /* complete required results with nil */
setnilvalue(s2v(where + i));
}
src/ltm.h
@@ -98,8 +98,8 @@
LUAI_FUNC void luaT_adjustvarargs (lua_State *L, struct CallInfo *ci,
const Proto *p);
LUAI_FUNC void luaT_getvararg (CallInfo *ci, StkId ra, TValue *rc);
-LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
- StkId where, int wanted);
+LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci, StkId where,
+ int wanted, int vatab);
#endif
src/luac.c
@@ -347,6 +347,8 @@
int bx=GETARG_Bx(i);
int sb=GETARG_sB(i);
int sc=GETARG_sC(i);
+ int vb=GETARG_vB(i);
+ int vc=GETARG_vC(i);
int sbx=GETARG_sBx(i);
int isk=GETARG_k(i);
int line=luaG_getfuncline(f,pc);
@@ -428,8 +430,8 @@
if (isk) { printf(" "); PrintConstant(f,c); }
break;
case OP_NEWTABLE:
- printf("%d %d %d",a,b,c);
- printf(COMMENT "%d",c+EXTRAARGC);
+ printf("%d %d %d%s",a,vb,vc,ISK);
+ printf(COMMENT "%d",vc+EXTRAARGC);
break;
case OP_SELF:
printf("%d %d %d%s",a,b,c,ISK);
@@ -633,7 +635,7 @@
printf(COMMENT "to %d",pc-bx+2);
break;
case OP_SETLIST:
- printf("%d %d %d",a,b,c);
+ printf("%d %d %d%s",a,vb,vc,ISK);
if (isk) printf(COMMENT "%d",c+EXTRAARGC);
break;
case OP_CLOSURE:
@@ -641,7 +643,7 @@
printf(COMMENT "%p",VOID(f->p[bx]));
break;
case OP_VARARG:
- printf("%d %d",a,c);
+ printf("%d %d %d%s",a,b,c,ISK);
printf(COMMENT);
if (c==0) printf("all out"); else printf("%d out",c-1);
break;
@@ -650,7 +652,8 @@
break;
case OP_ERRNNIL:
printf("%d %d",a,bx);
- printf(COMMENT); PrintConstant(f,bx);
+ printf(COMMENT);
+ if (bx==0) printf("?"); else PrintConstant(f,bx-1);
break;
case OP_VARARGPREP:
printf("%d",a);
@@ -686,7 +689,7 @@
f->linedefined,f->lastlinedefined,
S(f->sizecode),VOID(f));
printf("%d%s param%s, %d slot%s, %d upvalue%s, ",
- (int)(f->numparams),(f->flag & PF_ISVARARG)?"+":"",SS(f->numparams),
+ (int)(f->numparams),isvararg(f)?"+":"",SS(f->numparams),
S(f->maxstacksize),S(f->sizeupvalues));
printf("%d local%s, %d constant%s, %d function%s\n",
S(f->sizelocvars),S(f->sizek),S(f->sizep));
src/lvm.c
@@ -1935,8 +1935,9 @@
}
vmcase(OP_VARARG) {
StkId ra = RA(i);
- int n = GETARG_C(i) - 1; /* required results */
- Protect(luaT_getvarargs(L, ci, ra, n));
+ int n = GETARG_C(i) - 1; /* required results (-1 means all) */
+ int vatab = GETARG_k(i) ? GETARG_B(i) : -1;
+ Protect(luaT_getvarargs(L, ci, ra, n, vatab));
vmbreak;
}
vmcase(OP_GETVARG) {