From f33cc4ddec886ea499d7d41dd60cac5ddc5687db Mon Sep 17 00:00:00 2001 From: Roberto I Date: Wed, 26 Nov 2025 11:18:29 -0300 Subject: New conceptual model for vararg Conceptually, all functions get their vararg arguments in a vararg table. The storing of vararg arguments in the stack is always treated as an optimization. --- ltm.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 13 deletions(-) (limited to 'ltm.c') diff --git a/ltm.c b/ltm.c index 8d64235e..39ac59d4 100644 --- a/ltm.c +++ b/ltm.c @@ -242,6 +242,7 @@ static void createvarargtab (lua_State *L, StkId f, int n) { 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); } @@ -265,11 +266,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_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)); + 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->top.p += totalargs + 1; @@ -299,16 +300,53 @@ void luaT_getvararg (CallInfo *ci, StkId ra, TValue *rc) { } -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)); } -- cgit v1.2.3-55-g6feb