mirror of https://github.com/rusefi/lua.git
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.)
This commit is contained in:
parent
f6aab3ec1f
commit
1fb4d53925
6
lcode.c
6
lcode.c
|
@ -430,7 +430,7 @@ static int codesJ (FuncState *fs, OpCode o, int sj, int k) {
|
|||
/*
|
||||
** Emit an "extra argument" instruction (format 'iAx')
|
||||
*/
|
||||
static int codeextraarg (FuncState *fs, int a) {
|
||||
int luaK_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);
|
||||
codeextraarg(fs, k);
|
||||
luaK_codeextraarg(fs, k);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
@ -1687,7 +1687,7 @@ void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
|
|||
luaK_codeABC(fs, OP_SETLIST, base, b, c);
|
||||
else if (c <= MAXARG_Ax) {
|
||||
luaK_codeABC(fs, OP_SETLIST, base, b, 0);
|
||||
codeextraarg(fs, c);
|
||||
luaK_codeextraarg(fs, c);
|
||||
}
|
||||
else
|
||||
luaX_syntaxerror(fs->ls, "constructor too long");
|
||||
|
|
1
lcode.h
1
lcode.h
|
@ -55,6 +55,7 @@ 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);
|
||||
|
|
26
lobject.c
26
lobject.c
|
@ -29,32 +29,6 @@
|
|||
#include "lvm.h"
|
||||
|
||||
|
||||
/*
|
||||
** converts an integer to a "floating point byte", represented as
|
||||
** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if
|
||||
** eeeee != 0 and (xxx) otherwise.
|
||||
*/
|
||||
int luaO_int2fb (unsigned int x) {
|
||||
int e = 0; /* exponent */
|
||||
if (x < 8) return x;
|
||||
while (x >= (8 << 4)) { /* coarse steps */
|
||||
x = (x + 0xf) >> 4; /* x = ceil(x / 16) */
|
||||
e += 4;
|
||||
}
|
||||
while (x >= (8 << 1)) { /* fine steps */
|
||||
x = (x + 1) >> 1; /* x = ceil(x / 2) */
|
||||
e++;
|
||||
}
|
||||
return ((e+1) << 3) | (cast_int(x) - 8);
|
||||
}
|
||||
|
||||
|
||||
/* converts back */
|
||||
int luaO_fb2int (int x) {
|
||||
return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Computes ceil(log2(x))
|
||||
*/
|
||||
|
|
|
@ -734,8 +734,6 @@ typedef struct Table {
|
|||
/* size of buffer for 'luaO_utf8esc' function */
|
||||
#define UTF8BUFFSZ 8
|
||||
|
||||
LUAI_FUNC int luaO_int2fb (unsigned int x);
|
||||
LUAI_FUNC int luaO_fb2int (int x);
|
||||
LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x);
|
||||
LUAI_FUNC int luaO_ceillog2 (unsigned int x);
|
||||
LUAI_FUNC int luaO_rawarith (lua_State *L, int op, const TValue *p1,
|
||||
|
|
10
lopcodes.h
10
lopcodes.h
|
@ -324,7 +324,8 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
|
|||
(*) In OP_SETLIST, if (B == 0) then real B = 'top'; if (C == 0) then
|
||||
next 'instruction' is EXTRAARG(real C).
|
||||
|
||||
(*) In OP_LOADKX, the next 'instruction' is always EXTRAARG.
|
||||
(*) In OP_LOADKX and OP_NEWTABLE, the next 'instruction' is always
|
||||
EXTRAARG.
|
||||
|
||||
(*) For comparisons, k specifies what condition the test should accept
|
||||
(true or false).
|
||||
|
@ -375,4 +376,11 @@ LUAI_DDEC(const lu_byte luaP_opmodes[NUM_OPCODES];)
|
|||
#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
|
||||
|
|
37
lparser.c
37
lparser.c
|
@ -811,16 +811,16 @@ static void yindex (LexState *ls, expdesc *v) {
|
|||
*/
|
||||
|
||||
|
||||
struct ConsControl {
|
||||
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 tostore; /* number of array elements pending to be stored */
|
||||
};
|
||||
} ConsControl;
|
||||
|
||||
|
||||
static void recfield (LexState *ls, struct ConsControl *cc) {
|
||||
static void recfield (LexState *ls, ConsControl *cc) {
|
||||
/* recfield -> (NAME | '['exp']') = exp */
|
||||
FuncState *fs = ls->fs;
|
||||
int reg = ls->fs->freereg;
|
||||
|
@ -841,7 +841,7 @@ static void recfield (LexState *ls, struct ConsControl *cc) {
|
|||
}
|
||||
|
||||
|
||||
static void closelistfield (FuncState *fs, struct ConsControl *cc) {
|
||||
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;
|
||||
|
@ -852,7 +852,7 @@ static void closelistfield (FuncState *fs, struct ConsControl *cc) {
|
|||
}
|
||||
|
||||
|
||||
static void lastlistfield (FuncState *fs, struct ConsControl *cc) {
|
||||
static void lastlistfield (FuncState *fs, ConsControl *cc) {
|
||||
if (cc->tostore == 0) return;
|
||||
if (hasmultret(cc->v.k)) {
|
||||
luaK_setmultret(fs, &cc->v);
|
||||
|
@ -867,16 +867,15 @@ static void lastlistfield (FuncState *fs, struct ConsControl *cc) {
|
|||
}
|
||||
|
||||
|
||||
static void listfield (LexState *ls, struct ConsControl *cc) {
|
||||
static void listfield (LexState *ls, ConsControl *cc) {
|
||||
/* listfield -> exp */
|
||||
expr(ls, &cc->v);
|
||||
checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor");
|
||||
cc->na++;
|
||||
cc->tostore++;
|
||||
}
|
||||
|
||||
|
||||
static void field (LexState *ls, struct ConsControl *cc) {
|
||||
static void field (LexState *ls, ConsControl *cc) {
|
||||
/* field -> listfield | recfield */
|
||||
switch(ls->t.token) {
|
||||
case TK_NAME: { /* may be 'listfield' or 'recfield' */
|
||||
|
@ -898,13 +897,30 @@ static void field (LexState *ls, struct 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 -> ',' | ';' */
|
||||
FuncState *fs = ls->fs;
|
||||
int line = ls->linenumber;
|
||||
int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0);
|
||||
struct ConsControl cc;
|
||||
ConsControl cc;
|
||||
luaK_codeextraarg(fs, 0);
|
||||
cc.na = cc.nh = cc.tostore = 0;
|
||||
cc.t = t;
|
||||
init_exp(t, VRELOC, pc);
|
||||
|
@ -919,8 +935,7 @@ static void constructor (LexState *ls, expdesc *t) {
|
|||
} while (testnext(ls, ',') || testnext(ls, ';'));
|
||||
check_match(ls, '}', '{', line);
|
||||
lastlistfield(fs, &cc);
|
||||
SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */
|
||||
SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */
|
||||
settablesize(fs, &cc, pc);
|
||||
}
|
||||
|
||||
/* }====================================================================== */
|
||||
|
|
9
ltests.c
9
ltests.c
|
@ -1103,14 +1103,6 @@ static int doremote (lua_State *L) {
|
|||
}
|
||||
|
||||
|
||||
static int int2fb_aux (lua_State *L) {
|
||||
int b = luaO_int2fb((unsigned int)luaL_checkinteger(L, 1));
|
||||
lua_pushinteger(L, b);
|
||||
lua_pushinteger(L, (unsigned int)luaO_fb2int(b));
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
static int log2_aux (lua_State *L) {
|
||||
unsigned int x = (unsigned int)luaL_checkinteger(L, 1);
|
||||
lua_pushinteger(L, luaO_ceillog2(x));
|
||||
|
@ -1780,7 +1772,6 @@ static const struct luaL_Reg tests_funcs[] = {
|
|||
{"pobj", gc_printobj},
|
||||
{"getref", getref},
|
||||
{"hash", hash_query},
|
||||
{"int2fb", int2fb_aux},
|
||||
{"log2", log2_aux},
|
||||
{"limits", get_limits},
|
||||
{"listcode", listcode},
|
||||
|
|
6
lvm.c
6
lvm.c
|
@ -1250,11 +1250,15 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||
int b = GETARG_B(i);
|
||||
int c = GETARG_C(i);
|
||||
Table *t;
|
||||
c = (c == 0) ? 0 : 1 << (c - 1); /* size is 2^c */
|
||||
if (b >= LIMTABSZ)
|
||||
b += LFIELDS_PER_FLUSH * GETARG_Ax(*pc) - LIMTABSZ;
|
||||
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, luaO_fb2int(b), luaO_fb2int(c)); /* idem */
|
||||
luaH_resize(L, t, b, c); /* idem */
|
||||
checkGC(L, ra + 1);
|
||||
vmbreak;
|
||||
}
|
||||
|
|
|
@ -93,11 +93,13 @@ end
|
|||
-- some basic instructions
|
||||
check(function () -- function does not create upvalues
|
||||
(function () end){f()}
|
||||
end, 'CLOSURE', 'NEWTABLE', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN0')
|
||||
end, 'CLOSURE', 'NEWTABLE', 'EXTRAARG', 'GETTABUP', 'CALL',
|
||||
'SETLIST', 'CALL', 'RETURN0')
|
||||
|
||||
check(function (x) -- function creates upvalues
|
||||
(function () return x end){f()}
|
||||
end, 'CLOSURE', 'NEWTABLE', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN')
|
||||
end, 'CLOSURE', 'NEWTABLE', 'EXTRAARG', 'GETTABUP', 'CALL',
|
||||
'SETLIST', 'CALL', 'RETURN')
|
||||
|
||||
|
||||
-- sequence of LOADNILs
|
||||
|
|
|
@ -49,33 +49,13 @@ if not T then
|
|||
else --[
|
||||
-- testing table sizes
|
||||
|
||||
local function log2 (x) return math.log(x, 2) end
|
||||
|
||||
local function mp2 (n) -- minimum power of 2 >= n
|
||||
local mp = 2^math.ceil(log2(n))
|
||||
local mp = 2^math.ceil(math.log(n, 2))
|
||||
assert(n == 0 or (mp/2 < n and n <= mp))
|
||||
return mp
|
||||
end
|
||||
|
||||
local function fb (n)
|
||||
local r, nn = T.int2fb(n)
|
||||
assert(r < 256)
|
||||
return nn
|
||||
end
|
||||
|
||||
-- test fb function
|
||||
for a = 1, 10000 do -- all numbers up to 10^4
|
||||
local n = fb(a)
|
||||
assert(a <= n and n <= a*1.125)
|
||||
end
|
||||
local a = 1024 -- plus a few up to 2 ^30
|
||||
local lim = 2^30
|
||||
while a < lim do
|
||||
local n = fb(a)
|
||||
assert(a <= n and n <= a*1.125)
|
||||
a = math.ceil(a*1.3)
|
||||
end
|
||||
|
||||
|
||||
local function check (t, na, nh)
|
||||
local a, h = T.querytab(t)
|
||||
|
@ -95,24 +75,30 @@ end
|
|||
|
||||
|
||||
-- testing constructor sizes
|
||||
local lim = 40
|
||||
local s = 'return {'
|
||||
for i=1,lim do
|
||||
s = s..i..','
|
||||
local s = s
|
||||
for k=0,lim do
|
||||
local t = load(s..'}', '')()
|
||||
assert(#t == i)
|
||||
check(t, fb(i), mp2(k))
|
||||
s = string.format('%sa%d=%d,', s, k, k)
|
||||
local sizes = {0, 1, 2, 3, 4, 5, 7, 8, 9, 15, 16, 17,
|
||||
30, 31, 32, 33, 34, 500, 1000}
|
||||
|
||||
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 _, sh in ipairs(sizes) do -- 'sh' is size of the hash part
|
||||
for j = 1, sh do -- 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))()
|
||||
assert(#t == sa)
|
||||
check(t, sa, mp2(sh))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- tests with unknown number of elements
|
||||
local a = {}
|
||||
for i=1,lim do a[i] = i end -- build auxiliary table
|
||||
for k=0,lim do
|
||||
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)
|
||||
|
|
Loading…
Reference in New Issue