aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-07-12 16:13:50 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-07-12 16:13:50 -0300
commit1fb4d539254b67e7e35ed698250c66d1edff0e08 (patch)
tree8f48b7ca736a7fb02834bcfac1415cd43307f529
parentf6aab3ec1f111cd8d968bdcb7ca800e93b819d24 (diff)
downloadlua-1fb4d539254b67e7e35ed698250c66d1edff0e08.tar.gz
lua-1fb4d539254b67e7e35ed698250c66d1edff0e08.tar.bz2
lua-1fb4d539254b67e7e35ed698250c66d1edff0e08.zip
OP_NEWTABLE keeps exact size of arrays
OP_NEWTABLE is followed by an OP_EXTRAARG, so that it can keep the exact size of the array part of the table to be created. (Functions 'luaO_int2fb'/'luaO_fb2int' were removed.)
-rw-r--r--lcode.c6
-rw-r--r--lcode.h1
-rw-r--r--lobject.c26
-rw-r--r--lobject.h2
-rw-r--r--lopcodes.h10
-rw-r--r--lparser.c37
-rw-r--r--ltests.c9
-rw-r--r--lvm.c6
-rw-r--r--testes/code.lua6
-rw-r--r--testes/nextvar.lua52
10 files changed, 67 insertions, 88 deletions
diff --git a/lcode.c b/lcode.c
index 74ff47de..1ff32ed7 100644
--- a/lcode.c
+++ b/lcode.c
@@ -430,7 +430,7 @@ static int codesJ (FuncState *fs, OpCode o, int sj, int k) {
430/* 430/*
431** Emit an "extra argument" instruction (format 'iAx') 431** Emit an "extra argument" instruction (format 'iAx')
432*/ 432*/
433static int codeextraarg (FuncState *fs, int a) { 433int luaK_codeextraarg (FuncState *fs, int a) {
434 lua_assert(a <= MAXARG_Ax); 434 lua_assert(a <= MAXARG_Ax);
435 return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a)); 435 return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a));
436} 436}
@@ -446,7 +446,7 @@ static int luaK_codek (FuncState *fs, int reg, int k) {
446 return luaK_codeABx(fs, OP_LOADK, reg, k); 446 return luaK_codeABx(fs, OP_LOADK, reg, k);
447 else { 447 else {
448 int p = luaK_codeABx(fs, OP_LOADKX, reg, 0); 448 int p = luaK_codeABx(fs, OP_LOADKX, reg, 0);
449 codeextraarg(fs, k); 449 luaK_codeextraarg(fs, k);
450 return p; 450 return p;
451 } 451 }
452} 452}
@@ -1687,7 +1687,7 @@ void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
1687 luaK_codeABC(fs, OP_SETLIST, base, b, c); 1687 luaK_codeABC(fs, OP_SETLIST, base, b, c);
1688 else if (c <= MAXARG_Ax) { 1688 else if (c <= MAXARG_Ax) {
1689 luaK_codeABC(fs, OP_SETLIST, base, b, 0); 1689 luaK_codeABC(fs, OP_SETLIST, base, b, 0);
1690 codeextraarg(fs, c); 1690 luaK_codeextraarg(fs, c);
1691 } 1691 }
1692 else 1692 else
1693 luaX_syntaxerror(fs->ls, "constructor too long"); 1693 luaX_syntaxerror(fs->ls, "constructor too long");
diff --git a/lcode.h b/lcode.h
index a15b6875..a924722c 100644
--- a/lcode.h
+++ b/lcode.h
@@ -55,6 +55,7 @@ LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
55LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx); 55LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx);
56LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, 56LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A,
57 int B, int C, int k); 57 int B, int C, int k);
58LUAI_FUNC int luaK_codeextraarg (FuncState *fs, int a);
58LUAI_FUNC int luaK_isKint (expdesc *e); 59LUAI_FUNC int luaK_isKint (expdesc *e);
59LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v); 60LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v);
60LUAI_FUNC void luaK_fixline (FuncState *fs, int line); 61LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
diff --git a/lobject.c b/lobject.c
index 2c265f96..b4efae4f 100644
--- a/lobject.c
+++ b/lobject.c
@@ -30,32 +30,6 @@
30 30
31 31
32/* 32/*
33** converts an integer to a "floating point byte", represented as
34** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if
35** eeeee != 0 and (xxx) otherwise.
36*/
37int luaO_int2fb (unsigned int x) {
38 int e = 0; /* exponent */
39 if (x < 8) return x;
40 while (x >= (8 << 4)) { /* coarse steps */
41 x = (x + 0xf) >> 4; /* x = ceil(x / 16) */
42 e += 4;
43 }
44 while (x >= (8 << 1)) { /* fine steps */
45 x = (x + 1) >> 1; /* x = ceil(x / 2) */
46 e++;
47 }
48 return ((e+1) << 3) | (cast_int(x) - 8);
49}
50
51
52/* converts back */
53int luaO_fb2int (int x) {
54 return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1);
55}
56
57
58/*
59** Computes ceil(log2(x)) 33** Computes ceil(log2(x))
60*/ 34*/
61int luaO_ceillog2 (unsigned int x) { 35int luaO_ceillog2 (unsigned int x) {
diff --git a/lobject.h b/lobject.h
index 2f95bcb5..95f8e188 100644
--- a/lobject.h
+++ b/lobject.h
@@ -734,8 +734,6 @@ typedef struct Table {
734/* size of buffer for 'luaO_utf8esc' function */ 734/* size of buffer for 'luaO_utf8esc' function */
735#define UTF8BUFFSZ 8 735#define UTF8BUFFSZ 8
736 736
737LUAI_FUNC int luaO_int2fb (unsigned int x);
738LUAI_FUNC int luaO_fb2int (int x);
739LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x); 737LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x);
740LUAI_FUNC int luaO_ceillog2 (unsigned int x); 738LUAI_FUNC int luaO_ceillog2 (unsigned int x);
741LUAI_FUNC int luaO_rawarith (lua_State *L, int op, const TValue *p1, 739LUAI_FUNC int luaO_rawarith (lua_State *L, int op, const TValue *p1,
diff --git a/lopcodes.h b/lopcodes.h
index 7bbbb0e5..0b23fa6f 100644
--- a/lopcodes.h
+++ b/lopcodes.h
@@ -324,7 +324,8 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
324 (*) In OP_SETLIST, if (B == 0) then real B = 'top'; if (C == 0) then 324 (*) In OP_SETLIST, if (B == 0) then real B = 'top'; if (C == 0) then
325 next 'instruction' is EXTRAARG(real C). 325 next 'instruction' is EXTRAARG(real C).
326 326
327 (*) In OP_LOADKX, the next 'instruction' is always EXTRAARG. 327 (*) In OP_LOADKX and OP_NEWTABLE, the next 'instruction' is always
328 EXTRAARG.
328 329
329 (*) For comparisons, k specifies what condition the test should accept 330 (*) For comparisons, k specifies what condition the test should accept
330 (true or false). 331 (true or false).
@@ -375,4 +376,11 @@ LUAI_DDEC(const lu_byte luaP_opmodes[NUM_OPCODES];)
375#define LFIELDS_PER_FLUSH 50 376#define LFIELDS_PER_FLUSH 50
376 377
377 378
379/*
380** In OP_NEWTABLE, array sizes smaller than LIMTABSZ are represented
381** directly in R(B). Otherwise, array size is given by
382** (R(B) - LIMTABSZ) + EXTRAARG * LFIELDS_PER_FLUSH
383*/
384#define LIMTABSZ (MAXARG_B - LFIELDS_PER_FLUSH)
385
378#endif 386#endif
diff --git a/lparser.c b/lparser.c
index 79df0217..193e50f1 100644
--- a/lparser.c
+++ b/lparser.c
@@ -811,16 +811,16 @@ static void yindex (LexState *ls, expdesc *v) {
811*/ 811*/
812 812
813 813
814struct ConsControl { 814typedef struct ConsControl {
815 expdesc v; /* last list item read */ 815 expdesc v; /* last list item read */
816 expdesc *t; /* table descriptor */ 816 expdesc *t; /* table descriptor */
817 int nh; /* total number of 'record' elements */ 817 int nh; /* total number of 'record' elements */
818 int na; /* total number of array elements */ 818 int na; /* total number of array elements */
819 int tostore; /* number of array elements pending to be stored */ 819 int tostore; /* number of array elements pending to be stored */
820}; 820} ConsControl;
821 821
822 822
823static void recfield (LexState *ls, struct ConsControl *cc) { 823static void recfield (LexState *ls, ConsControl *cc) {
824 /* recfield -> (NAME | '['exp']') = exp */ 824 /* recfield -> (NAME | '['exp']') = exp */
825 FuncState *fs = ls->fs; 825 FuncState *fs = ls->fs;
826 int reg = ls->fs->freereg; 826 int reg = ls->fs->freereg;
@@ -841,7 +841,7 @@ static void recfield (LexState *ls, struct ConsControl *cc) {
841} 841}
842 842
843 843
844static void closelistfield (FuncState *fs, struct ConsControl *cc) { 844static void closelistfield (FuncState *fs, ConsControl *cc) {
845 if (cc->v.k == VVOID) return; /* there is no list item */ 845 if (cc->v.k == VVOID) return; /* there is no list item */
846 luaK_exp2nextreg(fs, &cc->v); 846 luaK_exp2nextreg(fs, &cc->v);
847 cc->v.k = VVOID; 847 cc->v.k = VVOID;
@@ -852,7 +852,7 @@ static void closelistfield (FuncState *fs, struct ConsControl *cc) {
852} 852}
853 853
854 854
855static void lastlistfield (FuncState *fs, struct ConsControl *cc) { 855static void lastlistfield (FuncState *fs, ConsControl *cc) {
856 if (cc->tostore == 0) return; 856 if (cc->tostore == 0) return;
857 if (hasmultret(cc->v.k)) { 857 if (hasmultret(cc->v.k)) {
858 luaK_setmultret(fs, &cc->v); 858 luaK_setmultret(fs, &cc->v);
@@ -867,16 +867,15 @@ static void lastlistfield (FuncState *fs, struct ConsControl *cc) {
867} 867}
868 868
869 869
870static void listfield (LexState *ls, struct ConsControl *cc) { 870static void listfield (LexState *ls, ConsControl *cc) {
871 /* listfield -> exp */ 871 /* listfield -> exp */
872 expr(ls, &cc->v); 872 expr(ls, &cc->v);
873 checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor");
874 cc->na++; 873 cc->na++;
875 cc->tostore++; 874 cc->tostore++;
876} 875}
877 876
878 877
879static void field (LexState *ls, struct ConsControl *cc) { 878static void field (LexState *ls, ConsControl *cc) {
880 /* field -> listfield | recfield */ 879 /* field -> listfield | recfield */
881 switch(ls->t.token) { 880 switch(ls->t.token) {
882 case TK_NAME: { /* may be 'listfield' or 'recfield' */ 881 case TK_NAME: { /* may be 'listfield' or 'recfield' */
@@ -898,13 +897,30 @@ static void field (LexState *ls, struct ConsControl *cc) {
898} 897}
899 898
900 899
900static void settablesize (FuncState *fs, ConsControl *cc, int pc) {
901 Instruction *inst = &fs->f->code[pc];
902 int rc = (cc->nh == 0) ? 0 : luaO_ceillog2(cc->nh) + 1;
903 int rb = cc->na;
904 int extra = 0;
905 if (rb >= LIMTABSZ) {
906 extra = rb / LFIELDS_PER_FLUSH;
907 rb = rb % LFIELDS_PER_FLUSH + LIMTABSZ;
908 checklimit(fs, extra, MAXARG_Ax, "items in a constructor");
909 }
910 SETARG_C(*inst, rc); /* set initial table size */
911 SETARG_B(*inst, rb); /* set initial array size */
912 SETARG_Ax(*(inst + 1), extra);
913}
914
915
901static void constructor (LexState *ls, expdesc *t) { 916static void constructor (LexState *ls, expdesc *t) {
902 /* constructor -> '{' [ field { sep field } [sep] ] '}' 917 /* constructor -> '{' [ field { sep field } [sep] ] '}'
903 sep -> ',' | ';' */ 918 sep -> ',' | ';' */
904 FuncState *fs = ls->fs; 919 FuncState *fs = ls->fs;
905 int line = ls->linenumber; 920 int line = ls->linenumber;
906 int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); 921 int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0);
907 struct ConsControl cc; 922 ConsControl cc;
923 luaK_codeextraarg(fs, 0);
908 cc.na = cc.nh = cc.tostore = 0; 924 cc.na = cc.nh = cc.tostore = 0;
909 cc.t = t; 925 cc.t = t;
910 init_exp(t, VRELOC, pc); 926 init_exp(t, VRELOC, pc);
@@ -919,8 +935,7 @@ static void constructor (LexState *ls, expdesc *t) {
919 } while (testnext(ls, ',') || testnext(ls, ';')); 935 } while (testnext(ls, ',') || testnext(ls, ';'));
920 check_match(ls, '}', '{', line); 936 check_match(ls, '}', '{', line);
921 lastlistfield(fs, &cc); 937 lastlistfield(fs, &cc);
922 SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ 938 settablesize(fs, &cc, pc);
923 SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */
924} 939}
925 940
926/* }====================================================================== */ 941/* }====================================================================== */
diff --git a/ltests.c b/ltests.c
index dc830657..cb8c422a 100644
--- a/ltests.c
+++ b/ltests.c
@@ -1103,14 +1103,6 @@ static int doremote (lua_State *L) {
1103} 1103}
1104 1104
1105 1105
1106static int int2fb_aux (lua_State *L) {
1107 int b = luaO_int2fb((unsigned int)luaL_checkinteger(L, 1));
1108 lua_pushinteger(L, b);
1109 lua_pushinteger(L, (unsigned int)luaO_fb2int(b));
1110 return 2;
1111}
1112
1113
1114static int log2_aux (lua_State *L) { 1106static int log2_aux (lua_State *L) {
1115 unsigned int x = (unsigned int)luaL_checkinteger(L, 1); 1107 unsigned int x = (unsigned int)luaL_checkinteger(L, 1);
1116 lua_pushinteger(L, luaO_ceillog2(x)); 1108 lua_pushinteger(L, luaO_ceillog2(x));
@@ -1780,7 +1772,6 @@ static const struct luaL_Reg tests_funcs[] = {
1780 {"pobj", gc_printobj}, 1772 {"pobj", gc_printobj},
1781 {"getref", getref}, 1773 {"getref", getref},
1782 {"hash", hash_query}, 1774 {"hash", hash_query},
1783 {"int2fb", int2fb_aux},
1784 {"log2", log2_aux}, 1775 {"log2", log2_aux},
1785 {"limits", get_limits}, 1776 {"limits", get_limits},
1786 {"listcode", listcode}, 1777 {"listcode", listcode},
diff --git a/lvm.c b/lvm.c
index a52f186f..4011819d 100644
--- a/lvm.c
+++ b/lvm.c
@@ -1250,11 +1250,15 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
1250 int b = GETARG_B(i); 1250 int b = GETARG_B(i);
1251 int c = GETARG_C(i); 1251 int c = GETARG_C(i);
1252 Table *t; 1252 Table *t;
1253 c = (c == 0) ? 0 : 1 << (c - 1); /* size is 2^c */
1254 if (b >= LIMTABSZ)
1255 b += LFIELDS_PER_FLUSH * GETARG_Ax(*pc) - LIMTABSZ;
1256 pc++; /* skip extra argument */
1253 L->top = ci->top; /* correct top in case of GC */ 1257 L->top = ci->top; /* correct top in case of GC */
1254 t = luaH_new(L); /* memory allocation */ 1258 t = luaH_new(L); /* memory allocation */
1255 sethvalue2s(L, ra, t); 1259 sethvalue2s(L, ra, t);
1256 if (b != 0 || c != 0) 1260 if (b != 0 || c != 0)
1257 luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); /* idem */ 1261 luaH_resize(L, t, b, c); /* idem */
1258 checkGC(L, ra + 1); 1262 checkGC(L, ra + 1);
1259 vmbreak; 1263 vmbreak;
1260 } 1264 }
diff --git a/testes/code.lua b/testes/code.lua
index 49d682f8..b2702c61 100644
--- a/testes/code.lua
+++ b/testes/code.lua
@@ -93,11 +93,13 @@ end
93-- some basic instructions 93-- some basic instructions
94check(function () -- function does not create upvalues 94check(function () -- function does not create upvalues
95 (function () end){f()} 95 (function () end){f()}
96end, 'CLOSURE', 'NEWTABLE', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN0') 96end, 'CLOSURE', 'NEWTABLE', 'EXTRAARG', 'GETTABUP', 'CALL',
97 'SETLIST', 'CALL', 'RETURN0')
97 98
98check(function (x) -- function creates upvalues 99check(function (x) -- function creates upvalues
99 (function () return x end){f()} 100 (function () return x end){f()}
100end, 'CLOSURE', 'NEWTABLE', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN') 101end, 'CLOSURE', 'NEWTABLE', 'EXTRAARG', 'GETTABUP', 'CALL',
102 'SETLIST', 'CALL', 'RETURN')
101 103
102 104
103-- sequence of LOADNILs 105-- sequence of LOADNILs
diff --git a/testes/nextvar.lua b/testes/nextvar.lua
index 87a6bfa8..bdc9fc29 100644
--- a/testes/nextvar.lua
+++ b/testes/nextvar.lua
@@ -49,33 +49,13 @@ if not T then
49else --[ 49else --[
50-- testing table sizes 50-- testing table sizes
51 51
52local function log2 (x) return math.log(x, 2) end
53 52
54local function mp2 (n) -- minimum power of 2 >= n 53local function mp2 (n) -- minimum power of 2 >= n
55 local mp = 2^math.ceil(log2(n)) 54 local mp = 2^math.ceil(math.log(n, 2))
56 assert(n == 0 or (mp/2 < n and n <= mp)) 55 assert(n == 0 or (mp/2 < n and n <= mp))
57 return mp 56 return mp
58end 57end
59 58
60local function fb (n)
61 local r, nn = T.int2fb(n)
62 assert(r < 256)
63 return nn
64end
65
66-- test fb function
67for a = 1, 10000 do -- all numbers up to 10^4
68 local n = fb(a)
69 assert(a <= n and n <= a*1.125)
70end
71local a = 1024 -- plus a few up to 2 ^30
72local lim = 2^30
73while a < lim do
74 local n = fb(a)
75 assert(a <= n and n <= a*1.125)
76 a = math.ceil(a*1.3)
77end
78
79 59
80local function check (t, na, nh) 60local function check (t, na, nh)
81 local a, h = T.querytab(t) 61 local a, h = T.querytab(t)
@@ -95,24 +75,30 @@ end
95 75
96 76
97-- testing constructor sizes 77-- testing constructor sizes
98local lim = 40 78local sizes = {0, 1, 2, 3, 4, 5, 7, 8, 9, 15, 16, 17,
99local s = 'return {' 79 30, 31, 32, 33, 34, 500, 1000}
100for i=1,lim do 80
101 s = s..i..',' 81for _, sa in ipairs(sizes) do -- 'sa' is size of the array part
102 local s = s 82 local arr = {"return {"}
103 for k=0,lim do 83 -- array part
104 local t = load(s..'}', '')() 84 for i = 1, sa do arr[1 + i] = "1," end
105 assert(#t == i) 85 for _, sh in ipairs(sizes) do -- 'sh' is size of the hash part
106 check(t, fb(i), mp2(k)) 86 for j = 1, sh do -- hash part
107 s = string.format('%sa%d=%d,', s, k, k) 87 arr[1 + sa + j] = string.format('k%x=%d,', j, j)
88 end
89 arr[1 + sa + sh + 1] = "}"
90 local prog = table.concat(arr)
91 local t = assert(load(prog))()
92 assert(#t == sa)
93 check(t, sa, mp2(sh))
108 end 94 end
109end 95end
110 96
111 97
112-- tests with unknown number of elements 98-- tests with unknown number of elements
113local a = {} 99local a = {}
114for i=1,lim do a[i] = i end -- build auxiliary table 100for i=1,sizes[#sizes] do a[i] = i end -- build auxiliary table
115for k=0,lim do 101for k in ipairs(sizes) do
116 local a = {table.unpack(a,1,k)} 102 local a = {table.unpack(a,1,k)}
117 assert(#a == k) 103 assert(#a == k)
118 check(a, k, 0) 104 check(a, k, 0)