diff options
| author | Roberto I <roberto@inf.puc-rio.br> | 2025-09-24 18:33:08 -0300 |
|---|---|---|
| committer | Roberto I <roberto@inf.puc-rio.br> | 2025-09-24 18:33:08 -0300 |
| commit | 25c54fe60e22d05cdfaa48c64372d354efa59547 (patch) | |
| tree | 3ccaeded5e4363db358f73b7c8fc6b9f414a2f2a /lcode.c | |
| parent | 0cc3c9447cca9abae9738ee77c24d88801c3916c (diff) | |
| download | lua-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.c | 57 |
1 files changed, 37 insertions, 20 deletions
| @@ -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 | */ |
| 1010 | void luaK_exp2anyregup (FuncState *fs, expdesc *e) { | 1016 | void 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 */ | ||
| 1324 | static 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; |
