diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2024-06-27 11:24:27 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2024-06-27 11:24:27 -0300 |
commit | 9904c253da9690728710082cfb94654709ab89e7 (patch) | |
tree | f556ebbf8d99baa37ea8e39608a3d6bea77f8267 | |
parent | fb7e5b76c9d41108c399cf4d16470018b717007b (diff) | |
download | lua-9904c253da9690728710082cfb94654709ab89e7.tar.gz lua-9904c253da9690728710082cfb94654709ab89e7.tar.bz2 lua-9904c253da9690728710082cfb94654709ab89e7.zip |
Flexible limit for use of registers by constructors
Instead of a fixed limit of 50 registers (which, in a bad worst case,
can limit the nesting of constructors to 5 levels), the compiler
computes an individual limit for each constructor based on how many
registers are available when it runs. This limit then controls the
frequency of SETLIST instructions.
Diffstat (limited to '')
-rw-r--r-- | lcode.c | 2 | ||||
-rw-r--r-- | lopcodes.h | 3 | ||||
-rw-r--r-- | lparser.c | 21 | ||||
-rw-r--r-- | ltests.c | 1 | ||||
-rw-r--r-- | testes/code.lua | 11 |
5 files changed, 31 insertions, 7 deletions
@@ -1804,7 +1804,7 @@ void luaK_settablesize (FuncState *fs, int pc, int ra, int asize, int hsize) { | |||
1804 | ** table (or LUA_MULTRET to add up to stack top). | 1804 | ** table (or LUA_MULTRET to add up to stack top). |
1805 | */ | 1805 | */ |
1806 | void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { | 1806 | void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { |
1807 | lua_assert(tostore != 0 && tostore <= LFIELDS_PER_FLUSH); | 1807 | lua_assert(tostore != 0); |
1808 | if (tostore == LUA_MULTRET) | 1808 | if (tostore == LUA_MULTRET) |
1809 | tostore = 0; | 1809 | tostore = 0; |
1810 | if (nelems <= MAXARG_C) | 1810 | if (nelems <= MAXARG_C) |
@@ -406,7 +406,4 @@ LUAI_DDEC(const lu_byte luaP_opmodes[NUM_OPCODES];) | |||
406 | (((mm) << 7) | ((ot) << 6) | ((it) << 5) | ((t) << 4) | ((a) << 3) | (m)) | 406 | (((mm) << 7) | ((ot) << 6) | ((it) << 5) | ((t) << 4) | ((a) << 3) | (m)) |
407 | 407 | ||
408 | 408 | ||
409 | /* number of list items to accumulate before a SETLIST instruction */ | ||
410 | #define LFIELDS_PER_FLUSH 50 | ||
411 | |||
412 | #endif | 409 | #endif |
@@ -843,13 +843,13 @@ static void yindex (LexState *ls, expdesc *v) { | |||
843 | ** ======================================================================= | 843 | ** ======================================================================= |
844 | */ | 844 | */ |
845 | 845 | ||
846 | |||
847 | typedef struct ConsControl { | 846 | typedef struct ConsControl { |
848 | expdesc v; /* last list item read */ | 847 | expdesc v; /* last list item read */ |
849 | expdesc *t; /* table descriptor */ | 848 | expdesc *t; /* table descriptor */ |
850 | int nh; /* total number of 'record' elements */ | 849 | int nh; /* total number of 'record' elements */ |
851 | int na; /* number of array elements already stored */ | 850 | int na; /* number of array elements already stored */ |
852 | int tostore; /* number of array elements pending to be stored */ | 851 | int tostore; /* number of array elements pending to be stored */ |
852 | int maxtostore; /* maximum number of pending elements */ | ||
853 | } ConsControl; | 853 | } ConsControl; |
854 | 854 | ||
855 | 855 | ||
@@ -878,7 +878,7 @@ static void closelistfield (FuncState *fs, ConsControl *cc) { | |||
878 | if (cc->v.k == VVOID) return; /* there is no list item */ | 878 | if (cc->v.k == VVOID) return; /* there is no list item */ |
879 | luaK_exp2nextreg(fs, &cc->v); | 879 | luaK_exp2nextreg(fs, &cc->v); |
880 | cc->v.k = VVOID; | 880 | cc->v.k = VVOID; |
881 | if (cc->tostore == LFIELDS_PER_FLUSH) { | 881 | if (cc->tostore >= cc->maxtostore) { |
882 | luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); /* flush */ | 882 | luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); /* flush */ |
883 | cc->na += cc->tostore; | 883 | cc->na += cc->tostore; |
884 | cc->tostore = 0; /* no more items pending */ | 884 | cc->tostore = 0; /* no more items pending */ |
@@ -931,6 +931,22 @@ static void field (LexState *ls, ConsControl *cc) { | |||
931 | } | 931 | } |
932 | 932 | ||
933 | 933 | ||
934 | /* | ||
935 | ** Compute a limit for how many registers a constructor can use before | ||
936 | ** emitting a 'SETLIST' instruction, based on how many registers are | ||
937 | ** available. | ||
938 | */ | ||
939 | static int maxtostore (FuncState *fs) { | ||
940 | int numfreeregs = MAX_FSTACK - fs->freereg; | ||
941 | if (numfreeregs >= 160) /* "lots" of registers? */ | ||
942 | return numfreeregs / 5u; /* use up to 1/5 of them */ | ||
943 | else if (numfreeregs >= 80) /* still "enough" registers? */ | ||
944 | return 10; /* one 'SETLIST' instruction for each 10 values */ | ||
945 | else /* save registers for potential more nesting */ | ||
946 | return 1; | ||
947 | } | ||
948 | |||
949 | |||
934 | static void constructor (LexState *ls, expdesc *t) { | 950 | static void constructor (LexState *ls, expdesc *t) { |
935 | /* constructor -> '{' [ field { sep field } [sep] ] '}' | 951 | /* constructor -> '{' [ field { sep field } [sep] ] '}' |
936 | sep -> ',' | ';' */ | 952 | sep -> ',' | ';' */ |
@@ -945,6 +961,7 @@ static void constructor (LexState *ls, expdesc *t) { | |||
945 | luaK_reserveregs(fs, 1); | 961 | luaK_reserveregs(fs, 1); |
946 | init_exp(&cc.v, VVOID, 0); /* no value (yet) */ | 962 | init_exp(&cc.v, VVOID, 0); /* no value (yet) */ |
947 | checknext(ls, '{'); | 963 | checknext(ls, '{'); |
964 | cc.maxtostore = maxtostore(fs); | ||
948 | do { | 965 | do { |
949 | lua_assert(cc.v.k == VVOID || cc.tostore > 0); | 966 | lua_assert(cc.v.k == VVOID || cc.tostore > 0); |
950 | if (ls->t.token == '}') break; | 967 | if (ls->t.token == '}') break; |
@@ -835,7 +835,6 @@ static int get_limits (lua_State *L) { | |||
835 | setnameval(L, "MAXARG_Ax", MAXARG_Ax); | 835 | setnameval(L, "MAXARG_Ax", MAXARG_Ax); |
836 | setnameval(L, "MAXARG_Bx", MAXARG_Bx); | 836 | setnameval(L, "MAXARG_Bx", MAXARG_Bx); |
837 | setnameval(L, "OFFSET_sBx", OFFSET_sBx); | 837 | setnameval(L, "OFFSET_sBx", OFFSET_sBx); |
838 | setnameval(L, "LFPF", LFIELDS_PER_FLUSH); | ||
839 | setnameval(L, "NUM_OPCODES", NUM_OPCODES); | 838 | setnameval(L, "NUM_OPCODES", NUM_OPCODES); |
840 | return 1; | 839 | return 1; |
841 | } | 840 | } |
diff --git a/testes/code.lua b/testes/code.lua index 329619f1..08b3e23f 100644 --- a/testes/code.lua +++ b/testes/code.lua | |||
@@ -460,5 +460,16 @@ do -- check number of available registers | |||
460 | assert(string.find(msg, "too many registers")) | 460 | assert(string.find(msg, "too many registers")) |
461 | end | 461 | end |
462 | 462 | ||
463 | |||
464 | do -- basic check for SETLIST | ||
465 | -- create a list constructor with 50 elements | ||
466 | local source = "local a; return {" .. string.rep("a, ", 50) .. "}" | ||
467 | local func = assert(load(source)) | ||
468 | local code = table.concat(T.listcode(func), "\n") | ||
469 | local _, count = string.gsub(code, "SETLIST", "") | ||
470 | -- code uses only 1 SETLIST for the constructor | ||
471 | assert(count == 1) | ||
472 | end | ||
473 | |||
463 | print 'OK' | 474 | print 'OK' |
464 | 475 | ||