diff --git a/lcode.c b/lcode.c index 1ff32ed7..a0d7757a 100644 --- a/lcode.c +++ b/lcode.c @@ -372,7 +372,7 @@ static void removelastinstruction (FuncState *fs) { ** Emit instruction 'i', checking for array sizes and saving also its ** line information. Return 'i' position. */ -static int luaK_code (FuncState *fs, Instruction i) { +int luaK_code (FuncState *fs, Instruction i) { Proto *f = fs->f; /* put new instruction in code array */ luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction, @@ -430,7 +430,7 @@ static int codesJ (FuncState *fs, OpCode o, int sj, int k) { /* ** Emit an "extra argument" instruction (format 'iAx') */ -int luaK_codeextraarg (FuncState *fs, int a) { +static int codeextraarg (FuncState *fs, int a) { lua_assert(a <= MAXARG_Ax); return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a)); } @@ -446,7 +446,7 @@ static int luaK_codek (FuncState *fs, int reg, int k) { return luaK_codeABx(fs, OP_LOADK, reg, k); else { int p = luaK_codeABx(fs, OP_LOADKX, reg, 0); - luaK_codeextraarg(fs, k); + codeextraarg(fs, k); return p; } } @@ -1672,6 +1672,22 @@ void luaK_fixline (FuncState *fs, int line) { } +void luaK_settablesize (FuncState *fs, int pc, int ra, int rc, int rb) { + Instruction *inst = &fs->f->code[pc]; + int extra = 0; + int k = 0; + if (rb != 0) + rb = luaO_ceillog2(rb) + 1; /* hash size */ + if (rc > MAXARG_C) { /* does it need the extra argument? */ + extra = rc / (MAXARG_C + 1); + rc %= (MAXARG_C + 1); + k = 1; + } + *inst = CREATE_ABCk(OP_NEWTABLE, ra, rb, rc, k); + *(inst + 1) = CREATE_Ax(OP_EXTRAARG, extra); +} + + /* ** Emit a SETLIST instruction. ** 'base' is register that keeps table; @@ -1680,17 +1696,17 @@ void luaK_fixline (FuncState *fs, int line) { ** table (or LUA_MULTRET to add up to stack top). */ void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { - int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; - int b = (tostore == LUA_MULTRET) ? 0 : tostore; lua_assert(tostore != 0 && tostore <= LFIELDS_PER_FLUSH); - if (c <= MAXARG_C) - luaK_codeABC(fs, OP_SETLIST, base, b, c); - else if (c <= MAXARG_Ax) { - luaK_codeABC(fs, OP_SETLIST, base, b, 0); - luaK_codeextraarg(fs, c); + if (tostore == LUA_MULTRET) + tostore = 0; + if (nelems <= MAXARG_C) + luaK_codeABC(fs, OP_SETLIST, base, tostore, nelems); + else { + int extra = nelems / (MAXARG_C + 1); + nelems %= (MAXARG_C + 1); + luaK_codeABCk(fs, OP_SETLIST, base, tostore, nelems, 1); + codeextraarg(fs, extra); } - else - luaX_syntaxerror(fs->ls, "constructor too long"); fs->freereg = base + 1; /* free registers with list values */ } diff --git a/lcode.h b/lcode.h index a924722c..0c12bb64 100644 --- a/lcode.h +++ b/lcode.h @@ -51,11 +51,11 @@ typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; #define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) +LUAI_FUNC int luaK_code (FuncState *fs, Instruction i); LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx); LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, int B, int C, int k); -LUAI_FUNC int luaK_codeextraarg (FuncState *fs, int a); LUAI_FUNC int luaK_isKint (expdesc *e); LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v); LUAI_FUNC void luaK_fixline (FuncState *fs, int line); @@ -87,6 +87,8 @@ LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line); LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2, int line); +LUAI_FUNC void luaK_settablesize (FuncState *fs, int pc, + int ra, int rb, int rc); LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); LUAI_FUNC void luaK_finish (FuncState *fs); LUAI_FUNC l_noret luaK_semerror (LexState *ls, const char *msg); diff --git a/lopcodes.h b/lopcodes.h index 0b23fa6f..371cb3ae 100644 --- a/lopcodes.h +++ b/lopcodes.h @@ -214,7 +214,7 @@ OP_SETTABLE,/* A B C R(A)[R(B)] := RK(C) */ OP_SETI,/* A B C R(A)[B] := RK(C) */ OP_SETFIELD,/* A B C R(A)[K(B):string] := RK(C) */ -OP_NEWTABLE,/* A B C R(A) := {} (size = B,C) */ +OP_NEWTABLE,/* A B C R(A) := {} */ OP_SELF,/* A B C R(A+1) := R(B); R(A) := R(B)[RK(C):string] */ @@ -321,12 +321,17 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ (*) In OP_RETURN, if (B == 0) then return up to 'top'. - (*) In OP_SETLIST, if (B == 0) then real B = 'top'; if (C == 0) then - next 'instruction' is EXTRAARG(real C). - - (*) In OP_LOADKX and OP_NEWTABLE, the next 'instruction' is always + (*) In OP_LOADKX and OP_NEWTABLE, the next instruction is always EXTRAARG. + (*) In OP_SETLIST, if (B == 0) then real B = 'top'; if k, then + real C = EXTRAARG _ C (the bits of EXTRAARG concatenated with the + bits of C). + + (*) In OP_NEWTABLE, B is log2 of the hash size (which is always a + power of 2) plus 1, or zero for size zero. If not k, the array size + is C. Otherwise, the array size is EXTRAARG _ C. + (*) For comparisons, k specifies what condition the test should accept (true or false). @@ -375,12 +380,4 @@ LUAI_DDEC(const lu_byte luaP_opmodes[NUM_OPCODES];) /* number of list items to accumulate before a SETLIST instruction */ #define LFIELDS_PER_FLUSH 50 - -/* -** In OP_NEWTABLE, array sizes smaller than LIMTABSZ are represented -** directly in R(B). Otherwise, array size is given by -** (R(B) - LIMTABSZ) + EXTRAARG * LFIELDS_PER_FLUSH -*/ -#define LIMTABSZ (MAXARG_B - LFIELDS_PER_FLUSH) - #endif diff --git a/lparser.c b/lparser.c index 193e50f1..ea810006 100644 --- a/lparser.c +++ b/lparser.c @@ -815,7 +815,7 @@ typedef struct ConsControl { expdesc v; /* last list item read */ expdesc *t; /* table descriptor */ int nh; /* total number of 'record' elements */ - int na; /* total number of array elements */ + int na; /* number of array elements already stored */ int tostore; /* number of array elements pending to be stored */ } ConsControl; @@ -847,6 +847,7 @@ static void closelistfield (FuncState *fs, ConsControl *cc) { cc->v.k = VVOID; if (cc->tostore == LFIELDS_PER_FLUSH) { luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); /* flush */ + cc->na += cc->tostore; cc->tostore = 0; /* no more items pending */ } } @@ -864,13 +865,13 @@ static void lastlistfield (FuncState *fs, ConsControl *cc) { luaK_exp2nextreg(fs, &cc->v); luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); } + cc->na += cc->tostore; } static void listfield (LexState *ls, ConsControl *cc) { /* listfield -> exp */ expr(ls, &cc->v); - cc->na++; cc->tostore++; } @@ -897,22 +898,6 @@ static void field (LexState *ls, ConsControl *cc) { } -static void settablesize (FuncState *fs, ConsControl *cc, int pc) { - Instruction *inst = &fs->f->code[pc]; - int rc = (cc->nh == 0) ? 0 : luaO_ceillog2(cc->nh) + 1; - int rb = cc->na; - int extra = 0; - if (rb >= LIMTABSZ) { - extra = rb / LFIELDS_PER_FLUSH; - rb = rb % LFIELDS_PER_FLUSH + LIMTABSZ; - checklimit(fs, extra, MAXARG_Ax, "items in a constructor"); - } - SETARG_C(*inst, rc); /* set initial table size */ - SETARG_B(*inst, rb); /* set initial array size */ - SETARG_Ax(*(inst + 1), extra); -} - - static void constructor (LexState *ls, expdesc *t) { /* constructor -> '{' [ field { sep field } [sep] ] '}' sep -> ',' | ';' */ @@ -920,12 +905,12 @@ static void constructor (LexState *ls, expdesc *t) { int line = ls->linenumber; int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); ConsControl cc; - luaK_codeextraarg(fs, 0); + luaK_code(fs, 0); /* space for extra arg. */ cc.na = cc.nh = cc.tostore = 0; cc.t = t; - init_exp(t, VRELOC, pc); + init_exp(t, VNONRELOC, fs->freereg); /* table will be at stack top */ + luaK_reserveregs(fs, 1); init_exp(&cc.v, VVOID, 0); /* no value (yet) */ - luaK_exp2nextreg(ls->fs, t); /* fix it at stack top */ checknext(ls, '{'); do { lua_assert(cc.v.k == VVOID || cc.tostore > 0); @@ -935,7 +920,7 @@ static void constructor (LexState *ls, expdesc *t) { } while (testnext(ls, ',') || testnext(ls, ';')); check_match(ls, '}', '{', line); lastlistfield(fs, &cc); - settablesize(fs, &cc, pc); + luaK_settablesize(fs, pc, t->u.info, cc.na, cc.nh); } /* }====================================================================== */ diff --git a/lvm.c b/lvm.c index ec65ea78..d365bcdd 100644 --- a/lvm.c +++ b/lvm.c @@ -1247,18 +1247,19 @@ void luaV_execute (lua_State *L, CallInfo *ci) { vmbreak; } vmcase(OP_NEWTABLE) { - int b = GETARG_B(i); - int c = GETARG_C(i); + int b = GETARG_B(i); /* log2(hash size) + 1 */ + int c = GETARG_C(i); /* array size */ Table *t; - c = (c == 0) ? 0 : 1 << (c - 1); /* size is 2^c */ - if (b >= LIMTABSZ) - b += LFIELDS_PER_FLUSH * GETARG_Ax(*pc) - LIMTABSZ; + if (b > 0) + b = 1 << (b - 1); /* size is 2^(b - 1) */ + if (TESTARG_k(i)) + c += GETARG_Ax(*pc) * (MAXARG_C + 1); pc++; /* skip extra argument */ L->top = ci->top; /* correct top in case of GC */ t = luaH_new(L); /* memory allocation */ sethvalue2s(L, ra, t); if (b != 0 || c != 0) - luaH_resize(L, t, b, c); /* idem */ + luaH_resize(L, t, c, b); /* idem */ checkGC(L, ra + 1); vmbreak; } @@ -1763,18 +1764,17 @@ void luaV_execute (lua_State *L, CallInfo *ci) { } vmcase(OP_SETLIST) { int n = GETARG_B(i); - int c = GETARG_C(i); - unsigned int last; - Table *h; + unsigned int last = GETARG_C(i); + Table *h = hvalue(s2v(ra)); if (n == 0) - n = cast_int(L->top - ra) - 1; + n = cast_int(L->top - ra) - 1; /* get up to the top */ else L->top = ci->top; /* correct top in case of GC */ - if (c == 0) { - c = GETARG_Ax(*pc); pc++; + last += n; + if (TESTARG_k(i)) { + last += GETARG_Ax(*pc) * (MAXARG_C + 1); + pc++; } - h = hvalue(s2v(ra)); - last = ((c-1)*LFIELDS_PER_FLUSH) + n; if (last > luaH_realasize(h)) /* needs more space? */ luaH_resizearray(L, h, last); /* preallocate it at once */ for (; n > 0; n--) { diff --git a/testes/nextvar.lua b/testes/nextvar.lua index bdc9fc29..a7fe625e 100644 --- a/testes/nextvar.lua +++ b/testes/nextvar.lua @@ -80,15 +80,23 @@ local sizes = {0, 1, 2, 3, 4, 5, 7, 8, 9, 15, 16, 17, for _, sa in ipairs(sizes) do -- 'sa' is size of the array part local arr = {"return {"} - -- array part - for i = 1, sa do arr[1 + i] = "1," end + for i = 1, sa do arr[1 + i] = "1," end -- build array part for _, sh in ipairs(sizes) do -- 'sh' is size of the hash part - for j = 1, sh do -- hash part + for j = 1, sh do -- build hash part arr[1 + sa + j] = string.format('k%x=%d,', j, j) end arr[1 + sa + sh + 1] = "}" local prog = table.concat(arr) - local t = assert(load(prog))() + local f = assert(load(prog)) + f() -- call once to ensure stack space + -- make sure table is not resized after being created + if sa == 0 or sh == 0 then + T.alloccount(2); -- header + array or hash part + else + T.alloccount(3); -- header + array part + hash part + end + local t = f() + T.alloccount(); assert(#t == sa) check(t, sa, mp2(sh)) end @@ -99,12 +107,12 @@ end local a = {} for i=1,sizes[#sizes] do a[i] = i end -- build auxiliary table for k in ipairs(sizes) do - local a = {table.unpack(a,1,k)} - assert(#a == k) - check(a, k, 0) - a = {1,2,3,table.unpack(a,1,k)} - check(a, k+3, 0) - assert(#a == k + 3) + local t = {table.unpack(a,1,k)} + assert(#t == k) + check(t, k, 0) + t = {1,2,3,table.unpack(a,1,k)} + check(t, k+3, 0) + assert(#t == k + 3) end