2
0
Эх сурвалжийг харах

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.
Roberto Ierusalimschy 1 жил өмнө
parent
commit
9904c253da
5 өөрчлөгдсөн 31 нэмэгдсэн , 7 устгасан
  1. 1 1
      lcode.c
  2. 0 3
      lopcodes.h
  3. 19 2
      lparser.c
  4. 0 1
      ltests.c
  5. 11 0
      testes/code.lua

+ 1 - 1
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)

+ 0 - 3
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

+ 19 - 2
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;

+ 0 - 1
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;
 }

+ 11 - 0
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'