From 25c54fe60e22d05cdfaa48c64372d354efa59547 Mon Sep 17 00:00:00 2001 From: Roberto I Date: Wed, 24 Sep 2025 18:33:08 -0300 Subject: Optimization for vararg tables A vararg table can be virtual. If the vararg table is used only as a base in indexing expressions, the code does not need to create an actual table for it. Instead, it compiles the indexing expressions into direct accesses to the internal vararg data. --- lcode.c | 57 +++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 20 deletions(-) (limited to 'lcode.c') diff --git a/lcode.c b/lcode.c index f74223eb..f7c2334c 100644 --- a/lcode.c +++ b/lcode.c @@ -842,6 +842,12 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { e->k = VRELOC; break; } + case VVARGIND: { + freeregs(fs, e->u.ind.t, e->u.ind.idx); + e->u.info = luaK_codeABC(fs, OP_GETVARG, 0, e->u.ind.t, e->u.ind.idx); + e->k = VRELOC; + break; + } case VVARARG: case VCALL: { luaK_setoneret(fs, e); break; @@ -1004,11 +1010,11 @@ int luaK_exp2anyreg (FuncState *fs, expdesc *e) { /* -** Ensures final expression result is either in a register -** or in an upvalue. +** Ensures final expression result is either in a register, +** in an upvalue, or it is the vararg parameter. */ void luaK_exp2anyregup (FuncState *fs, expdesc *e) { - if (e->k != VUPVAL || hasjumps(e)) + if ((e->k != VUPVAL && e->k != VVARGVAR) || hasjumps(e)) luaK_exp2anyreg(fs, e); } @@ -1314,6 +1320,13 @@ void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { } +/* auxiliary function to define indexing expressions */ +static void fillidxk (expdesc *t, int idx, expkind k) { + t->u.ind.idx = cast_byte(idx); + t->k = k; +} + + /* ** Create expression 't[k]'. 't' must have its final result already in a ** register or upvalue. Upvalues can only be indexed by literal strings. @@ -1325,31 +1338,30 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { if (k->k == VKSTR) keystr = str2K(fs, k); lua_assert(!hasjumps(t) && - (t->k == VLOCAL || t->k == VNONRELOC || t->k == VUPVAL)); + (t->k == VLOCAL || t->k == VVARGVAR || + t->k == VNONRELOC || t->k == VUPVAL)); if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non 'Kstr'? */ luaK_exp2anyreg(fs, t); /* put it in a register */ if (t->k == VUPVAL) { lu_byte temp = cast_byte(t->u.info); /* upvalue index */ t->u.ind.t = temp; /* (can't do a direct assignment; values overlap) */ lua_assert(isKstr(fs, k)); - t->u.ind.idx = cast_short(k->u.info); /* literal short string */ - t->k = VINDEXUP; + fillidxk(t, k->u.info, VINDEXUP); /* literal short string */ + } + else if (t->k == VVARGVAR) { /* indexing the vararg parameter? */ + lua_assert(t->u.ind.t == fs->f->numparams); + t->u.ind.t = cast_byte(t->u.var.ridx); + fillidxk(t, luaK_exp2anyreg(fs, k), VVARGIND); /* register */ } else { /* register index of the table */ t->u.ind.t = cast_byte((t->k == VLOCAL) ? t->u.var.ridx: t->u.info); - if (isKstr(fs, k)) { - t->u.ind.idx = cast_short(k->u.info); /* literal short string */ - t->k = VINDEXSTR; - } - else if (isCint(k)) { /* int. constant in proper range? */ - t->u.ind.idx = cast_short(k->u.ival); - t->k = VINDEXI; - } - else { - t->u.ind.idx = cast_short(luaK_exp2anyreg(fs, k)); /* register */ - t->k = VINDEXED; - } + if (isKstr(fs, k)) + fillidxk(t, k->u.info, VINDEXSTR); /* literal short string */ + else if (isCint(k)) /* int. constant in proper range? */ + fillidxk(t, cast_int(k->u.ival), VINDEXI); + else + fillidxk(t, luaK_exp2anyreg(fs, k), VINDEXED); /* register */ } t->u.ind.keystr = keystr; /* string index in 'k' */ t->u.ind.ro = 0; /* by default, not read-only */ @@ -1913,9 +1925,14 @@ void luaK_finish (FuncState *fs) { SETARG_C(*pc, p->numparams + 1); /* signal that it is vararg */ break; } - case OP_JMP: { + case OP_GETVARG: { + if (p->flag & PF_VATAB) /* function has a vararg table? */ + SET_OPCODE(*pc, OP_GETTABLE); /* must get vararg there */ + break; + } + case OP_JMP: { /* to optimize jumps to jumps */ int target = finaltarget(p->code, i); - fixjump(fs, i, target); + fixjump(fs, i, target); /* jump directly to final target */ break; } default: break; -- cgit v1.2.3-55-g6feb