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) { ** table (or LUA_MULTRET to add up to stack top). */ void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { - lua_assert(tostore != 0 && tostore <= LFIELDS_PER_FLUSH); + lua_assert(tostore != 0); if (tostore == LUA_MULTRET) tostore = 0; 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];) (((mm) << 7) | ((ot) << 6) | ((it) << 5) | ((t) << 4) | ((a) << 3) | (m)) -/* number of list items to accumulate before a SETLIST instruction */ -#define LFIELDS_PER_FLUSH 50 - #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) { ** ======================================================================= */ - typedef struct ConsControl { expdesc v; /* last list item read */ expdesc *t; /* table descriptor */ int nh; /* total number of 'record' elements */ int na; /* number of array elements already stored */ int tostore; /* number of array elements pending to be stored */ + int maxtostore; /* maximum number of pending elements */ } ConsControl; @@ -878,7 +878,7 @@ static void closelistfield (FuncState *fs, ConsControl *cc) { if (cc->v.k == VVOID) return; /* there is no list item */ luaK_exp2nextreg(fs, &cc->v); cc->v.k = VVOID; - if (cc->tostore == LFIELDS_PER_FLUSH) { + if (cc->tostore >= cc->maxtostore) { luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); /* flush */ cc->na += cc->tostore; cc->tostore = 0; /* no more items pending */ @@ -931,6 +931,22 @@ static void field (LexState *ls, ConsControl *cc) { } +/* +** Compute a limit for how many registers a constructor can use before +** emitting a 'SETLIST' instruction, based on how many registers are +** available. +*/ +static int maxtostore (FuncState *fs) { + int numfreeregs = MAX_FSTACK - fs->freereg; + if (numfreeregs >= 160) /* "lots" of registers? */ + return numfreeregs / 5u; /* use up to 1/5 of them */ + else if (numfreeregs >= 80) /* still "enough" registers? */ + return 10; /* one 'SETLIST' instruction for each 10 values */ + else /* save registers for potential more nesting */ + return 1; +} + + static void constructor (LexState *ls, expdesc *t) { /* constructor -> '{' [ field { sep field } [sep] ] '}' sep -> ',' | ';' */ @@ -945,6 +961,7 @@ static void constructor (LexState *ls, expdesc *t) { luaK_reserveregs(fs, 1); init_exp(&cc.v, VVOID, 0); /* no value (yet) */ checknext(ls, '{'); + cc.maxtostore = maxtostore(fs); do { lua_assert(cc.v.k == VVOID || cc.tostore > 0); 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) { setnameval(L, "MAXARG_Ax", MAXARG_Ax); setnameval(L, "MAXARG_Bx", MAXARG_Bx); setnameval(L, "OFFSET_sBx", OFFSET_sBx); - setnameval(L, "LFPF", LFIELDS_PER_FLUSH); setnameval(L, "NUM_OPCODES", NUM_OPCODES); return 1; } 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 assert(string.find(msg, "too many registers")) end + +do -- basic check for SETLIST + -- create a list constructor with 50 elements + local source = "local a; return {" .. string.rep("a, ", 50) .. "}" + local func = assert(load(source)) + local code = table.concat(T.listcode(func), "\n") + local _, count = string.gsub(code, "SETLIST", "") + -- code uses only 1 SETLIST for the constructor + assert(count == 1) +end + print 'OK'