aboutsummaryrefslogtreecommitdiff
path: root/lcode.c
diff options
context:
space:
mode:
authorRoberto I <roberto@inf.puc-rio.br>2025-09-24 18:33:08 -0300
committerRoberto I <roberto@inf.puc-rio.br>2025-09-24 18:33:08 -0300
commit25c54fe60e22d05cdfaa48c64372d354efa59547 (patch)
tree3ccaeded5e4363db358f73b7c8fc6b9f414a2f2a /lcode.c
parent0cc3c9447cca9abae9738ee77c24d88801c3916c (diff)
downloadlua-25c54fe60e22d05cdfaa48c64372d354efa59547.tar.gz
lua-25c54fe60e22d05cdfaa48c64372d354efa59547.tar.bz2
lua-25c54fe60e22d05cdfaa48c64372d354efa59547.zip
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.
Diffstat (limited to 'lcode.c')
-rw-r--r--lcode.c57
1 files changed, 37 insertions, 20 deletions
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) {
842 e->k = VRELOC; 842 e->k = VRELOC;
843 break; 843 break;
844 } 844 }
845 case VVARGIND: {
846 freeregs(fs, e->u.ind.t, e->u.ind.idx);
847 e->u.info = luaK_codeABC(fs, OP_GETVARG, 0, e->u.ind.t, e->u.ind.idx);
848 e->k = VRELOC;
849 break;
850 }
845 case VVARARG: case VCALL: { 851 case VVARARG: case VCALL: {
846 luaK_setoneret(fs, e); 852 luaK_setoneret(fs, e);
847 break; 853 break;
@@ -1004,11 +1010,11 @@ int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
1004 1010
1005 1011
1006/* 1012/*
1007** Ensures final expression result is either in a register 1013** Ensures final expression result is either in a register,
1008** or in an upvalue. 1014** in an upvalue, or it is the vararg parameter.
1009*/ 1015*/
1010void luaK_exp2anyregup (FuncState *fs, expdesc *e) { 1016void luaK_exp2anyregup (FuncState *fs, expdesc *e) {
1011 if (e->k != VUPVAL || hasjumps(e)) 1017 if ((e->k != VUPVAL && e->k != VVARGVAR) || hasjumps(e))
1012 luaK_exp2anyreg(fs, e); 1018 luaK_exp2anyreg(fs, e);
1013} 1019}
1014 1020
@@ -1314,6 +1320,13 @@ void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
1314} 1320}
1315 1321
1316 1322
1323/* auxiliary function to define indexing expressions */
1324static void fillidxk (expdesc *t, int idx, expkind k) {
1325 t->u.ind.idx = cast_byte(idx);
1326 t->k = k;
1327}
1328
1329
1317/* 1330/*
1318** Create expression 't[k]'. 't' must have its final result already in a 1331** Create expression 't[k]'. 't' must have its final result already in a
1319** register or upvalue. Upvalues can only be indexed by literal strings. 1332** register or upvalue. Upvalues can only be indexed by literal strings.
@@ -1325,31 +1338,30 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
1325 if (k->k == VKSTR) 1338 if (k->k == VKSTR)
1326 keystr = str2K(fs, k); 1339 keystr = str2K(fs, k);
1327 lua_assert(!hasjumps(t) && 1340 lua_assert(!hasjumps(t) &&
1328 (t->k == VLOCAL || t->k == VNONRELOC || t->k == VUPVAL)); 1341 (t->k == VLOCAL || t->k == VVARGVAR ||
1342 t->k == VNONRELOC || t->k == VUPVAL));
1329 if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non 'Kstr'? */ 1343 if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non 'Kstr'? */
1330 luaK_exp2anyreg(fs, t); /* put it in a register */ 1344 luaK_exp2anyreg(fs, t); /* put it in a register */
1331 if (t->k == VUPVAL) { 1345 if (t->k == VUPVAL) {
1332 lu_byte temp = cast_byte(t->u.info); /* upvalue index */ 1346 lu_byte temp = cast_byte(t->u.info); /* upvalue index */
1333 t->u.ind.t = temp; /* (can't do a direct assignment; values overlap) */ 1347 t->u.ind.t = temp; /* (can't do a direct assignment; values overlap) */
1334 lua_assert(isKstr(fs, k)); 1348 lua_assert(isKstr(fs, k));
1335 t->u.ind.idx = cast_short(k->u.info); /* literal short string */ 1349 fillidxk(t, k->u.info, VINDEXUP); /* literal short string */
1336 t->k = VINDEXUP; 1350 }
1351 else if (t->k == VVARGVAR) { /* indexing the vararg parameter? */
1352 lua_assert(t->u.ind.t == fs->f->numparams);
1353 t->u.ind.t = cast_byte(t->u.var.ridx);
1354 fillidxk(t, luaK_exp2anyreg(fs, k), VVARGIND); /* register */
1337 } 1355 }
1338 else { 1356 else {
1339 /* register index of the table */ 1357 /* register index of the table */
1340 t->u.ind.t = cast_byte((t->k == VLOCAL) ? t->u.var.ridx: t->u.info); 1358 t->u.ind.t = cast_byte((t->k == VLOCAL) ? t->u.var.ridx: t->u.info);
1341 if (isKstr(fs, k)) { 1359 if (isKstr(fs, k))
1342 t->u.ind.idx = cast_short(k->u.info); /* literal short string */ 1360 fillidxk(t, k->u.info, VINDEXSTR); /* literal short string */
1343 t->k = VINDEXSTR; 1361 else if (isCint(k)) /* int. constant in proper range? */
1344 } 1362 fillidxk(t, cast_int(k->u.ival), VINDEXI);
1345 else if (isCint(k)) { /* int. constant in proper range? */ 1363 else
1346 t->u.ind.idx = cast_short(k->u.ival); 1364 fillidxk(t, luaK_exp2anyreg(fs, k), VINDEXED); /* register */
1347 t->k = VINDEXI;
1348 }
1349 else {
1350 t->u.ind.idx = cast_short(luaK_exp2anyreg(fs, k)); /* register */
1351 t->k = VINDEXED;
1352 }
1353 } 1365 }
1354 t->u.ind.keystr = keystr; /* string index in 'k' */ 1366 t->u.ind.keystr = keystr; /* string index in 'k' */
1355 t->u.ind.ro = 0; /* by default, not read-only */ 1367 t->u.ind.ro = 0; /* by default, not read-only */
@@ -1913,9 +1925,14 @@ void luaK_finish (FuncState *fs) {
1913 SETARG_C(*pc, p->numparams + 1); /* signal that it is vararg */ 1925 SETARG_C(*pc, p->numparams + 1); /* signal that it is vararg */
1914 break; 1926 break;
1915 } 1927 }
1916 case OP_JMP: { 1928 case OP_GETVARG: {
1929 if (p->flag & PF_VATAB) /* function has a vararg table? */
1930 SET_OPCODE(*pc, OP_GETTABLE); /* must get vararg there */
1931 break;
1932 }
1933 case OP_JMP: { /* to optimize jumps to jumps */
1917 int target = finaltarget(p->code, i); 1934 int target = finaltarget(p->code, i);
1918 fixjump(fs, i, target); 1935 fixjump(fs, i, target); /* jump directly to final target */
1919 break; 1936 break;
1920 } 1937 }
1921 default: break; 1938 default: break;