aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2024-06-27 11:24:27 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2024-06-27 11:24:27 -0300
commit9904c253da9690728710082cfb94654709ab89e7 (patch)
treef556ebbf8d99baa37ea8e39608a3d6bea77f8267
parentfb7e5b76c9d41108c399cf4d16470018b717007b (diff)
downloadlua-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.c2
-rw-r--r--lopcodes.h3
-rw-r--r--lparser.c21
-rw-r--r--ltests.c1
-rw-r--r--testes/code.lua11
5 files changed, 31 insertions, 7 deletions
diff --git a/lcode.c b/lcode.c
index bc0a3341..a74c2a16 100644
--- a/lcode.c
+++ b/lcode.c
@@ -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*/
1806void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { 1806void 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)
diff --git a/lopcodes.h b/lopcodes.h
index 235c51f6..1d31e7c5 100644
--- a/lopcodes.h
+++ b/lopcodes.h
@@ -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
diff --git a/lparser.c b/lparser.c
index cdc8cf42..f3779864 100644
--- a/lparser.c
+++ b/lparser.c
@@ -843,13 +843,13 @@ static void yindex (LexState *ls, expdesc *v) {
843** ======================================================================= 843** =======================================================================
844*/ 844*/
845 845
846
847typedef struct ConsControl { 846typedef 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*/
939static 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
934static void constructor (LexState *ls, expdesc *t) { 950static 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;
diff --git a/ltests.c b/ltests.c
index 1f69fe03..2b8db375 100644
--- a/ltests.c
+++ b/ltests.c
@@ -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"))
461end 461end
462 462
463
464do -- 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)
472end
473
463print 'OK' 474print 'OK'
464 475