diff --git a/src/blua/lapi.c b/src/blua/lapi.c index 557896f43..0c78bc851 100644 --- a/src/blua/lapi.c +++ b/src/blua/lapi.c @@ -519,6 +519,23 @@ LUA_API int lua_pushthread (lua_State *L) { ** get functions (Lua -> stack) */ +static void auxgetstr (lua_State *L, const TValue *t, const char *k) { + const TValue *slot; + TValue key; + TString *str = luaS_new(L, k); + api_checkvalidindex(L, t); + if (luaV_fastget(L, t, str, slot, luaH_getstr)) { + setobj2s(L, L->top, slot); + api_incr_top(L); + } + else { + setsvalue(L, &key, str); + luaV_finishget(L, t, L->top, L->top, slot); + api_incr_top(L); + } + lua_unlock(L); +} + LUA_API void lua_gettable (lua_State *L, int idx) { StkId t; @@ -531,15 +548,8 @@ LUA_API void lua_gettable (lua_State *L, int idx) { LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { - StkId t; - TValue key; lua_lock(L); - t = index2adr(L, idx); - api_checkvalidindex(L, t); - setsvalue(L, &key, luaS_new(L, k)); - luaV_gettable(L, t, &key, L->top); - api_incr_top(L); - lua_unlock(L); + auxgetstr(L, index2adr(L, idx), k); } @@ -630,6 +640,26 @@ LUA_API void lua_getfenv (lua_State *L, int idx) { ** set functions (stack -> Lua) */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +static void auxsetstr (lua_State *L, const TValue *t, const char *k) { + TValue key; + const TValue *slot; + TString *str = luaS_new(L, k); + api_checknelems(L, 1); + api_checkvalidindex(L, t); + if (luaV_fastset(L, t, str, slot, luaH_setstr, L->top)) { + setobj2t(L, cast(TValue *, slot), L->top - 1); + L->top--; /* pop value */ + } + else { + setsvalue2s(L, &key, str); + luaV_finishset(L, t, &key, L->top - 1, slot); + L->top--; /* pop value */ + } + lua_unlock(L); +} + LUA_API void lua_settable (lua_State *L, int idx) { StkId t; @@ -642,18 +672,12 @@ LUA_API void lua_settable (lua_State *L, int idx) { lua_unlock(L); } +#pragma GCC diagnostic pop + LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { - StkId t; - TValue key; lua_lock(L); - api_checknelems(L, 1); - t = index2adr(L, idx); - api_checkvalidindex(L, t); - setsvalue(L, &key, luaS_new(L, k)); - luaV_settable(L, t, &key, L->top - 1); - L->top--; /* pop value */ - lua_unlock(L); + auxsetstr(L, index2adr(L, idx), k); } diff --git a/src/blua/lauxlib.c b/src/blua/lauxlib.c index 5fb454d5e..05a115002 100644 --- a/src/blua/lauxlib.c +++ b/src/blua/lauxlib.c @@ -20,6 +20,7 @@ #define lauxlib_c #define LUA_LIB +#include "ldebug.h" #include "lua.h" #include "lauxlib.h" @@ -468,8 +469,19 @@ LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) { LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { - while (l--) - luaL_addchar(B, *s++); + while (l) { + size_t space = bufffree(B); + if (space == 0) { + luaL_prepbuffer(B); + lua_assert(bufffree(B) == LUAL_BUFFERSIZE); + space = LUAL_BUFFERSIZE; + } + if (space > l) space = l; + memcpy(B->p, s, space); + B->p += space; + s += space; + l -= space; + } } @@ -686,6 +698,6 @@ static int panic (lua_State *L) { LUALIB_API lua_State *luaL_newstate (void) { lua_State *L = lua_newstate(l_alloc, NULL); - if (L) lua_atpanic(L, &panic); + if (l_likely(L)) lua_atpanic(L, &panic); return L; } diff --git a/src/blua/lcode.c b/src/blua/lcode.c index efb20e96b..562ad3506 100644 --- a/src/blua/lcode.c +++ b/src/blua/lcode.c @@ -626,8 +626,20 @@ static void codenot (FuncState *fs, expdesc *e) { removevalues(fs, e->t); } +/* +** Check whether expression 'e' is a literal string +*/ +static int isKstr (FuncState *fs, expdesc *e) { + return (e->k == VK && ttisstring(&fs->f->k[e->u.s.info])); +} +/* +** Create expression 't[k]'. 't' must have its final result already in a +** register or upvalue. Upvalues can only be indexed by literal strings. +*/ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { + if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non string? */ + luaK_exp2anyreg(fs, t); /* put it in a register */ t->u.s.aux = luaK_exp2RK(fs, k); t->k = VINDEXED; } @@ -790,18 +802,19 @@ void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { case OPR_BXOR: codearith(fs, OP_BXOR, e1, e2); break; case OPR_BSHL: codearith(fs, OP_BSHL, e1, e2); break; case OPR_BSHR: codearith(fs, OP_BSHR, e1, e2); break; - case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break; - case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break; - case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break; - case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break; - case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break; - case OPR_POW: codearith(fs, OP_POW, e1, e2); break; - case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break; - case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break; - case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break; - case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break; - case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break; - case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break; + case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: + case OPR_MOD: case OPR_POW: { + codearith(fs, op - OPR_ADD + OP_ADD, e1, e2); + break; + } + case OPR_EQ: case OPR_LT: case OPR_LE: { + codecomp(fs, op - OPR_EQ + OP_EQ, 1, e1, e2); + break; + } + case OPR_NE: case OPR_GT: case OPR_GE: { + codecomp(fs, op - OPR_NE + OP_EQ, 0, e1, e2); + break; + } default: lua_assert(0); } } diff --git a/src/blua/lcode.h b/src/blua/lcode.h index 5b8009472..b15c1bfeb 100644 --- a/src/blua/lcode.h +++ b/src/blua/lcode.h @@ -21,13 +21,13 @@ /* -** grep "ORDER OPR" if you change these enums +** grep "ORDER OPR" if you change these enums (ORDER OP) */ typedef enum BinOpr { OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, OPR_CONCAT, - OPR_NE, OPR_EQ, - OPR_LT, OPR_LE, OPR_GT, OPR_GE, + OPR_EQ, OPR_LT, OPR_LE, + OPR_NE, OPR_GT, OPR_GE, OPR_AND, OPR_OR, OPR_BAND, OPR_BOR, OPR_BXOR, OPR_BSHL, OPR_BSHR, diff --git a/src/blua/ldebug.c b/src/blua/ldebug.c index 542e209a1..e209fae5d 100644 --- a/src/blua/ldebug.c +++ b/src/blua/ldebug.c @@ -542,16 +542,39 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int stackpos, static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { + TMS tm = 0; Instruction i; if ((isLua(ci) && ci->tailcalls > 0) || !isLua(ci - 1)) return NULL; /* calling function is not Lua (or is unknown) */ ci--; /* calling function */ i = ci_func(ci)->l.p->code[currentpc(L, ci)]; - if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || - GET_OPCODE(i) == OP_TFORLOOP) - return getobjname(L, ci, GETARG_A(i), name); - else - return NULL; /* no useful name can be found */ + switch (GET_OPCODE(i)) { + case OP_CALL: + case OP_TAILCALL: + case OP_TFORLOOP: + return getobjname(L, ci, GETARG_A(i), name); + case OP_GETGLOBAL: + case OP_SELF: + case OP_GETTABLE: tm = TM_INDEX; break; + case OP_SETGLOBAL: + case OP_SETTABLE: tm = TM_NEWINDEX; break; + case OP_EQ: tm = TM_EQ; break; + case OP_ADD: tm = TM_ADD; break; + case OP_SUB: tm = TM_SUB; break; + case OP_MUL: tm = TM_MUL; break; + case OP_DIV: tm = TM_DIV; break; + case OP_MOD: tm = TM_MOD; break; + case OP_POW: tm = TM_POW; break; + case OP_UNM: tm = TM_UNM; break; + case OP_LEN: tm = TM_LEN; break; + case OP_LT: tm = TM_LT; break; + case OP_LE: tm = TM_LE; break; + case OP_CONCAT: tm = TM_CONCAT; break; + default: + return NULL; /* else no useful name can be found */ + } + *name = getstr(G(L)->tmname[tm]); + return "metamethod"; } diff --git a/src/blua/ldo.c b/src/blua/ldo.c index c573dab17..1bda07f11 100644 --- a/src/blua/ldo.c +++ b/src/blua/ldo.c @@ -164,7 +164,7 @@ void luaD_reallocCI (lua_State *L, int newsize) { void luaD_growstack (lua_State *L, int n) { - if (l_likely(n <= L->stacksize)) /* double size is enough? */ + if (n <= L->stacksize) /* double size is enough? */ luaD_reallocstack(L, 2*L->stacksize); else luaD_reallocstack(L, L->stacksize + n); @@ -318,7 +318,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { ci->top = L->top + LUA_MINSTACK; lua_assert(ci->top <= L->stack_last); ci->nresults = nresults; - if (L->hookmask & LUA_MASKCALL) + if (l_unlikely(L->hookmask & LUA_MASKCALL)) luaD_callhook(L, LUA_HOOKCALL, -1); lua_unlock(L); n = (*curr_func(L)->c.f)(L); /* do the actual call */ diff --git a/src/blua/liolib.c b/src/blua/liolib.c index 2cd8dd481..2ef46c6a6 100644 --- a/src/blua/liolib.c +++ b/src/blua/liolib.c @@ -356,20 +356,21 @@ static int read_line (lua_State *L, FILE *f) { static int read_chars (lua_State *L, FILE *f, size_t n) { - size_t rlen; /* how much to read */ - size_t nr; /* number of chars actually read */ + size_t tbr = n; /* number of chars to be read */ + size_t rlen; /* how much to read in each cycle */ + size_t nr; /* number of chars actually read in each cycle */ luaL_Buffer b; luaL_buffinit(L, &b); rlen = LUAL_BUFFERSIZE; /* try to read that much each time */ do { char *p = luaL_prepbuffer(&b); - if (rlen > n) rlen = n; /* cannot read more than asked */ + if (rlen > tbr) rlen = tbr; /* cannot read more than asked */ nr = fread(p, sizeof(char), rlen, f); luaL_addsize(&b, nr); - n -= nr; /* still have to read `n' chars */ - } while (n > 0 && nr == rlen); /* until end of count or eof */ + tbr -= nr; /* still have to read 'tbr' chars */ + } while (tbr > 0 && nr == rlen); /* until end of count or eof */ luaL_pushresult(&b); /* close buffer */ - return (n == 0 || lua_objlen(L, -1) > 0); + return (tbr == 0 || tbr < n); /* true iff read something */ } @@ -432,13 +433,13 @@ static int f_read (lua_State *L) { static int io_readline (lua_State *L) { FILE *f = *(FILE **)lua_touserdata(L, lua_upvalueindex(1)); - int sucess; + int success; if (f == NULL) /* file is already closed? */ luaL_error(L, "file is already closed"); - sucess = read_line(L, f); + success = read_line(L, f); if (ferror(f)) return luaL_error(L, "%s", strerror(errno)); - if (sucess) return 1; + if (success) return 1; else { /* EOF */ if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */ lua_settop(L, 0); diff --git a/src/blua/lopcodes.h b/src/blua/lopcodes.h index 8b08b04e0..aa84da8d0 100644 --- a/src/blua/lopcodes.h +++ b/src/blua/lopcodes.h @@ -232,6 +232,8 @@ OP_VARARG/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */ (*) In OP_SETLIST, if (B == 0) then B = `top'; if (C == 0) then next `instruction' is real C + (*) In OP_SELF, the index must be a string. + (*) For comparisons, A specifies what condition the test should accept (true or false). diff --git a/src/blua/lparser.c b/src/blua/lparser.c index 871c9730d..8046b0f1f 100644 --- a/src/blua/lparser.c +++ b/src/blua/lparser.c @@ -881,10 +881,10 @@ static const struct { lu_byte right; /* right priority */ } priority[] = { /* ORDER OPR */ {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, /* `+' `-' `/' `%' */ - {10, 9}, {5, 4}, /* power and concat (right associative) */ - {3, 3}, {3, 3}, /* equality and inequality */ - {3, 3}, {3, 3}, {3, 3}, {3, 3}, /* order */ - {2, 2}, {1, 1} /* logical (and/or) */ + {10, 9}, {5, 4}, /* ^, .. (right associative) */ + {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */ + {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */ + {2, 2}, {1, 1} /* and, or */ ,{6, 6}, {6, 6}, {6, 6}, /* bit-wise (band/bor/bxor) */ {7, 7}, {7, 7} /* shl/shr */ }; diff --git a/src/blua/lstring.c b/src/blua/lstring.c index 0bcc30877..b1249238b 100644 --- a/src/blua/lstring.c +++ b/src/blua/lstring.c @@ -51,7 +51,7 @@ static TString *newlstr (lua_State *L, const char *str, size_t l, unsigned int h) { TString *ts; stringtable *tb; - if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) + if (l_unlikely(l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char))) luaM_toobig(L); ts = cast(TString *, luaM_malloc(L, (l+1)*sizeof(char)+sizeof(TString))); ts->tsv.len = l; @@ -72,18 +72,72 @@ static TString *newlstr (lua_State *L, const char *str, size_t l, } -TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { - GCObject *o; +// string hash taken from luaJIT + +/* Unaligned load of uint32_t. */ +static inline __attribute__((always_inline)) uint32_t getu32(const void* ptr) +{ + uint32_t result; + memcpy(&result, ptr, 4); + return result; +} + +// smol macro to look a little less messy lul +#define getu8(p) *cast(const uint8_t *, p) + +/* Keyed sparse ARX string hash. Constant time. */ +static unsigned hash_sparse(const char *str, size_t len) +{ + /* Constants taken from lookup3 hash by Bob Jenkins. */ + unsigned int a, b, h = cast(unsigned int, len); +#define rol(x, n) (((x)<<(n)) | ((x)>>(-cast(int, n)&(8*sizeof(x)-1)))) + if (len >= 4) { /* Caveat: unaligned access! */ + a = getu32(str); + h ^= getu32(str+len-4); + b = getu32(str+(len>>1)-2); + h ^= b; h -= rol(b, 14); + b += getu32(str+(len>>2)-1); + } else if (len > 0) { + a = getu8(str); + h ^= getu8(str+len-1); + b = getu8(str+(len>>1)); + h ^= b; h -= rol(b, 14); + } else { + return 0; + } + a ^= h; a -= rol(h, 11); + b ^= a; b -= rol(a, 25); + h ^= b; h -= rol(b, 16); +#undef rol + return h; +} + +#undef getu8 + + +static inline __attribute__((always_inline)) unsigned luaS_hash (const char *str, size_t l) { +#if 0 unsigned int h = cast(unsigned int, l); /* seed */ size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */ size_t l1; for (l1=l; l1>=step; l1-=step) /* compute hash */ h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1])); + return h; +#else + return hash_sparse(str, l); +#endif +} + +TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { + GCObject *o; + unsigned int h = luaS_hash(str, l); for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; o != NULL; o = o->gch.next) { TString *ts = rawgco2ts(o); - if (l_unlikely(ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0))) { + if (ts->tsv.hash == h && + ts->tsv.len == l && + (memcmp(str, getstr(ts), l) == 0)) { /* string may be dead */ if (isdead(G(L), o)) changewhite(o); return ts; diff --git a/src/blua/ltm.c b/src/blua/ltm.c index 031a2811e..22add1891 100644 --- a/src/blua/ltm.c +++ b/src/blua/ltm.c @@ -61,7 +61,7 @@ TValue *luaT_gettm (Table *events, TMS event, TString *ename) { } -TValue *luaT_gettmbyobj (lua_State *L, TValue *o, TMS event) { +TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) { Table *mt; switch (ttype(o)) { case LUA_TTABLE: diff --git a/src/blua/ltm.h b/src/blua/ltm.h index 3d4ac8c0e..08b07b20a 100644 --- a/src/blua/ltm.h +++ b/src/blua/ltm.h @@ -55,7 +55,7 @@ LUAI_DATA const char *const luaT_typenames[]; LUAI_FUNC TValue *luaT_gettm (Table *events, TMS event, TString *ename); -LUAI_FUNC TValue *luaT_gettmbyobj (lua_State *L, TValue *o, TMS event); +LUAI_FUNC TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event); LUAI_FUNC void luaT_init (lua_State *L); #endif diff --git a/src/blua/lvm.c b/src/blua/lvm.c index 02d2265c1..b7015e0a2 100644 --- a/src/blua/lvm.c +++ b/src/blua/lvm.c @@ -28,7 +28,7 @@ -/* limit for table tag-method chains (to avoid loops) */ +/* limit for table tag-method chains (to avoid infinite loops) */ #define MAXTAGLOOP 100 @@ -105,61 +105,94 @@ static void callTM (lua_State *L, const TValue *f, const TValue *p1, } -void luaV_gettable (lua_State *L, TValue *t, TValue *key, StkId val) { - int loop; +/* +** Finish the table access 'val = t[key]'. +** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to +** t[k] entry (which must be nil). +*/ +void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, + const TValue *slot) { + int loop; /* counter to avoid infinite loops */ + const TValue *tm; /* metamethod */ for (loop = 0; loop < MAXTAGLOOP; loop++) { - TValue *tm; - if (ttistable(t)) { /* `t' is a table? */ - Table *h = hvalue(t); - const TValue *res = luaH_get(h, key); /* do a primitive get */ - if (!ttisnil(res) || /* result is no nil? */ - (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ - setobj2s(L, val, res); + if (slot == NULL) { /* 't' is not a table? */ + lua_assert(!ttistable(t)); + tm = luaT_gettmbyobj(L, t, TM_INDEX); + if (l_unlikely(ttisnil(tm))) + luaG_typeerror(L, t, "index"); /* no metamethod */ + /* else will try the metamethod */ + } + else { /* 't' is a table */ + lua_assert(ttisnil(slot)); + tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */ + if (tm == NULL) { /* no metamethod? */ + setnilvalue(val); /* result is nil */ return; } - /* else will try the tag method */ + /* else will try the metamethod */ } - else if (l_unlikely(ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX)))) - luaG_typeerror(L, t, "index"); - if (ttisfunction(tm)) { - callTMres(L, val, tm, t, key); + if (ttisfunction(tm)) { /* is metamethod a function? */ + callTMres(L, val, tm, t, key); /* call it */ return; } - t = tm; /* else repeat with `tm' */ + t = tm; /* else try to access 'tm[key]' */ + if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */ + setobj2s(L, val, slot); /* done */ + return; + } + /* else repeat (tail call 'luaV_finishget') */ } - luaG_runerror(L, "loop in gettable"); + luaG_runerror(L, "'__index' chain too long; possible loop"); } - -void luaV_settable (lua_State *L, TValue *t, TValue *key, StkId val) { - int loop; +/* +** Finish a table assignment 't[key] = val'. +** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points +** to the entry 't[key]', or to 'luaO_nilobject' if there is no such +** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset' +** would have done the job.) +*/ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +void luaV_finishset (lua_State *L, const TValue *t, TValue *key, + StkId val, const TValue *slot) { + int loop; /* counter to avoid infinite loops */ for (loop = 0; loop < MAXTAGLOOP; loop++) { - TValue *tm = NULL; - if (ttistable(t)) { /* `t' is a table? */ + const TValue *tm; + if (slot != NULL) { + lua_assert(ttistable(t) && ttisnil(slot)); Table *h = hvalue(t); - TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ - /* oldval is nil=> look for newindex, oldval is not nil => look for usedindex */ - if (!((ttisnil(oldval) && ((tm = fasttm(L, h->metatable, TM_NEWINDEX)) != NULL)) || - ((!ttisnil(oldval)) && ((tm = fasttm(L, h->metatable, TM_USEDINDEX)) != NULL)))) { - setobj2t(L, oldval, val); + /* must check the metamethod */ + /* slot is nil=> look for newindex, slot is not nil => look for usedindex */ + if (!((ttisnil(slot) && ((tm = fasttm(L, h->metatable, TM_NEWINDEX)) != NULL)) || + ((!ttisnil(slot)) && ((tm = fasttm(L, h->metatable, TM_USEDINDEX)) != NULL)))) { + /* no metamethod and (now) there is an entry with given key */ + setobj2t(L, cast(TValue *, slot), val); luaC_barriert(L, h, val); return; } - /* else will try the tag method */ + /* else will try the metamethod */ } - else if (l_unlikely(ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))) - luaG_typeerror(L, t, "index"); + else { /* not a table; check metamethod */ + if (l_unlikely(ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))) + luaG_typeerror(L, t, "index"); + } + /* try the metamethod */ if (ttisfunction(tm)) { callTM(L, tm, t, key, val); return; } - t = tm; /* else repeat with `tm' */ + t = tm; /* else repeat assignment over 'tm' */ + if (luaV_fastset(L, t, key, slot, luaH_set, val)) + return; /* done */ + /* else loop */ } - luaG_runerror(L, "loop in settable"); + luaG_runerror(L, "settable chain too long; possible loop"); } +#pragma GCC diagnostic pop -static int call_binTM (lua_State *L, TValue *p1, TValue *p2, +static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, StkId res, TMS event) { const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ if (ttisnil(tm)) @@ -184,7 +217,7 @@ static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2, } -static int call_orderTM (lua_State *L, TValue *p1, TValue *p2, +static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, TMS event) { const TValue *tm1 = luaT_gettmbyobj(L, p1, event); const TValue *tm2; @@ -366,6 +399,7 @@ static void Arith (lua_State *L, StkId ra, TValue *rb, #define arith_op(op,tm) { \ + StkId ra = RA(i); \ TValue *rb = RKB(i); \ TValue *rc = RKC(i); \ if (ttisnumber(rb) && ttisnumber(rc)) { \ @@ -377,6 +411,24 @@ static void Arith (lua_State *L, StkId ra, TValue *rb, } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" + +/* +** copy of 'luaV_gettable', but protecting call to potential metamethod +** (which can reallocate the stack) +*/ +#define gettableProtected(L,t,k,v) { const TValue *slot; \ + if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \ + else Protect(luaV_finishget(L,t,k,v,slot)); } + + +/* same for 'luaV_settable' */ +#define settableProtected(L,t,k,v) { const TValue *slot; \ + if (!luaV_fastset(L,t,k,slot,luaH_set,v)) \ + Protect(luaV_finishset(L,t,k,v,slot)); } + + void luaV_execute (lua_State *L, int nexeccalls) { LClosure *cl; @@ -386,13 +438,12 @@ void luaV_execute (lua_State *L, int nexeccalls) { reentry: /* entry point */ lua_assert(isLua(L->ci)); pc = L->savedpc; - cl = &clvalue(L->ci->func)->l; - base = L->base; - k = cl->p->k; + cl = &clvalue(L->ci->func)->l; /* local reference to function's closure */ + k = cl->p->k; /* local reference to function's constant table */ + base = L->base; /* local copy of function's base */ /* main loop of interpreter */ for (;;) { const Instruction i = *pc++; - StkId ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { traceexec(L, pc); @@ -402,26 +453,28 @@ void luaV_execute (lua_State *L, int nexeccalls) { } base = L->base; } - /* warning!! several calls may realloc the stack and invalidate `ra' */ - ra = RA(i); lua_assert(base == L->base && L->base == L->ci->base); lua_assert(base <= L->top && L->top <= L->stack + L->stacksize); lua_assert(L->top == L->ci->top || luaG_checkopenop(i)); switch (GET_OPCODE(i)) { case OP_MOVE: { + StkId ra = RA(i); setobjs2s(L, ra, RB(i)); continue; } case OP_LOADK: { + StkId ra = RA(i); setobj2s(L, ra, KBx(i)); continue; } case OP_LOADBOOL: { + StkId ra = RA(i); setbvalue(ra, GETARG_B(i)); if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ continue; } case OP_LOADNIL: { + StkId ra = RA(i); TValue *rb = RB(i); do { setnilvalue(rb--); @@ -429,11 +482,13 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_GETUPVAL: { + StkId ra = RA(i); int b = GETARG_B(i); setobj2s(L, ra, cl->upvals[b]->v); continue; } case OP_GETGLOBAL: { + StkId ra = RA(i); TValue g; TValue *rb = KBx(i); sethvalue(L, &g, cl->env); @@ -442,10 +497,14 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_GETTABLE: { - Protect(luaV_gettable(L, RB(i), RKC(i), ra)); + StkId ra = RA(i); + StkId rb = RB(i); + TValue *rc = RKC(i); + gettableProtected(L, rb, rc, ra); continue; } case OP_SETGLOBAL: { + StkId ra = RA(i); TValue g; sethvalue(L, &g, cl->env); lua_assert(ttisstring(KBx(i))); @@ -453,16 +512,21 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_SETUPVAL: { + StkId ra = RA(i); UpVal *uv = cl->upvals[GETARG_B(i)]; setobj(L, uv->v, ra); luaC_barrier(L, uv, ra); continue; } case OP_SETTABLE: { - Protect(luaV_settable(L, ra, RKB(i), RKC(i))); + StkId ra = RA(i); + TValue *rb = RKB(i); + TValue *rc = RKC(i); + settableProtected(L, ra, rb, rc); continue; } case OP_NEWTABLE: { + StkId ra = RA(i); int b = GETARG_B(i); int c = GETARG_C(i); sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); @@ -470,9 +534,16 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_SELF: { + StkId ra = RA(i); + const TValue *slot; StkId rb = RB(i); - setobjs2s(L, ra+1, rb); - Protect(luaV_gettable(L, rb, RKC(i), ra)); + TValue *rc = RKC(i); + TString *key = rawtsvalue(rc); /* key must be a string */ + setobjs2s(L, ra + 1, rb); + if (luaV_fastget(L, rb, key, slot, luaH_getstr)) { + setobj2s(L, ra, slot); + } + else Protect(luaV_finishget(L, rb, rc, ra, slot)); continue; } case OP_ADD: { @@ -488,6 +559,7 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_DIV: { + StkId ra = RA(i); TValue *rb = RKB(i); TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { @@ -503,6 +575,7 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_MOD: { + StkId ra = RA(i); TValue *rb = RKB(i); TValue *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { @@ -522,26 +595,27 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_BAND: { - arith_op(luai_numand, TM_AND); - continue; + arith_op(luai_numand, TM_AND); + continue; } case OP_BOR: { - arith_op(luai_numor, TM_OR); - continue; + arith_op(luai_numor, TM_OR); + continue; } case OP_BXOR: { - arith_op(luai_numxor, TM_XOR); - continue; + arith_op(luai_numxor, TM_XOR); + continue; } case OP_BSHL: { - arith_op(luai_numshl, TM_SHL); - continue; + arith_op(luai_numshl, TM_SHL); + continue; } case OP_BSHR: { - arith_op(luai_numshr, TM_SHR); - continue; + arith_op(luai_numshr, TM_SHR); + continue; } case OP_BNOT: { + StkId ra = RA(i); TValue *rb = RB(i); if (ttisnumber(rb)) { lua_Number nb = nvalue(rb); @@ -553,6 +627,7 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_UNM: { + StkId ra = RA(i); TValue *rb = RB(i); if (ttisnumber(rb)) { lua_Number nb = nvalue(rb); @@ -564,11 +639,13 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_NOT: { + StkId ra = RA(i); int res = l_isfalse(RB(i)); /* next assignment may change this value */ setbvalue(ra, res); continue; } case OP_LEN: { + StkId ra = RA(i); TValue *rb = RB(i); switch (ttype(rb)) { case LUA_TTABLE: { @@ -626,12 +703,14 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_TEST: { + StkId ra = RA(i); if (l_isfalse(ra) != GETARG_C(i)) dojump(L, pc, GETARG_sBx(*pc)); pc++; continue; } case OP_TESTSET: { + StkId ra = RA(i); TValue *rb = RB(i); if (l_isfalse(rb) != GETARG_C(i)) { setobjs2s(L, ra, rb); @@ -641,6 +720,7 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_CALL: { + StkId ra = RA(i); int b = GETARG_B(i); int nresults = GETARG_C(i) - 1; if (b != 0) L->top = ra+b; /* else previous instruction set top */ @@ -662,6 +742,7 @@ void luaV_execute (lua_State *L, int nexeccalls) { } } case OP_TAILCALL: { + StkId ra = RA(i); int b = GETARG_B(i); if (b != 0) L->top = ra+b; /* else previous instruction set top */ L->savedpc = pc; @@ -694,6 +775,7 @@ void luaV_execute (lua_State *L, int nexeccalls) { } } case OP_RETURN: { + StkId ra = RA(i); int b = GETARG_B(i); if (b != 0) L->top = ra+b-1; if (L->openupval) luaF_close(L, base); @@ -709,6 +791,7 @@ void luaV_execute (lua_State *L, int nexeccalls) { } } case OP_FORLOOP: { + StkId ra = RA(i); lua_Number step = nvalue(ra+2); lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */ lua_Number limit = nvalue(ra+1); @@ -721,6 +804,7 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_FORPREP: { + StkId ra = RA(i); const TValue *init = ra; const TValue *plimit = ra+1; const TValue *pstep = ra+2; @@ -737,6 +821,7 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_TFORLOOP: { + StkId ra = RA(i); StkId cb = ra + 3; /* call base */ setobjs2s(L, cb+2, ra+2); setobjs2s(L, cb+1, ra+1); @@ -753,6 +838,7 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_SETLIST: { + StkId ra = RA(i); int n = GETARG_B(i); int c = GETARG_C(i); int last; @@ -775,10 +861,12 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_CLOSE: { + StkId ra = RA(i); luaF_close(L, ra); continue; } case OP_CLOSURE: { + StkId ra = RA(i); Proto *p; Closure *ncl; int nup, j; @@ -799,6 +887,7 @@ void luaV_execute (lua_State *L, int nexeccalls) { continue; } case OP_VARARG: { + StkId ra = RA(i); int b = GETARG_B(i) - 1; int j; CallInfo *ci = L->ci; @@ -822,3 +911,5 @@ void luaV_execute (lua_State *L, int nexeccalls) { } } } + +#pragma GCC diagnostic pop diff --git a/src/blua/lvm.h b/src/blua/lvm.h index f9226ee5d..a14ce827e 100644 --- a/src/blua/lvm.h +++ b/src/blua/lvm.h @@ -22,14 +22,61 @@ (ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2)) +/* +** fast track for 'gettable': if 't' is a table and 't[k]' is not nil, +** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise, +** return 0 (meaning it will have to check metamethod) with 'slot' +** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise). +** 'f' is the raw get function to use. +*/ +#define luaV_fastget(L,t,k,slot,f) \ + (!ttistable(t) \ + ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ + : (slot = f(hvalue(t), k), /* else, do raw access */ \ + !ttisnil(slot))) /* result not nil? */ + +/* +** standard implementation for 'gettable' +*/ +#define luaV_gettable(L,t,k,v) { const TValue *slot; \ + if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \ + else luaV_finishget(L,t,k,v,slot); } + + +/* +** Fast track for set table. If 't' is a table and 't[k]' is not nil, +** call GC barrier, do a raw 't[k]=v', and return true; otherwise, +** return false with 'slot' equal to NULL (if 't' is not a table) or +** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro +** returns true, there is no need to 'invalidateTMcache', because the +** call is not creating a new entry. +*/ +#define luaV_fastset(L,t,k,slot,f,v) \ + (!ttistable(t) \ + ? (slot = NULL, 0) \ + : (slot = f(L, hvalue(t), k), \ + ttisnil(slot) ? 0 \ + : (__extension__ ({ \ + if (valiswhite(v) && isblack(obj2gco(hvalue(t)))) \ + luaC_barrierback(L, hvalue(t)); \ + setobj2t(L, cast(TValue *,slot), v); \ + 1; \ + })))) + +#define luaV_settable(L,t,k,v) { const TValue *slot; \ + if (!luaV_fastset(L,t,k,slot,luaH_set,v)) \ + luaV_finishset(L,t,k,v,slot); } + + + LUAI_FUNC int luaV_lessthan (lua_State *L, TValue *l, TValue *r); LUAI_FUNC int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2); LUAI_FUNC const TValue *luaV_tonumber (const TValue *obj, TValue *n); LUAI_FUNC int luaV_tostring (lua_State *L, StkId obj); -LUAI_FUNC void luaV_gettable (lua_State *L, TValue *t, TValue *key, - StkId val); -LUAI_FUNC void luaV_settable (lua_State *L, TValue *t, TValue *key, - StkId val); +LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, + StkId val, const TValue *tm); +LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, + StkId val, const TValue *oldval); LUAI_FUNC void luaV_execute (lua_State *L, int nexeccalls); LUAI_FUNC void luaV_concat (lua_State *L, int total, int last);