'luaV_fastget' only treats the real fast case (table with a non-nil

value at given key, so that it does not need to check metamethods)
This commit is contained in:
Roberto Ierusalimschy 2016-01-05 14:07:21 -02:00
parent a272fa66f0
commit 1a44e82200
3 changed files with 67 additions and 55 deletions

30
lapi.c
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lapi.c,v 2.256 2015/10/06 16:10:22 roberto Exp roberto $ ** $Id: lapi.c,v 2.257 2015/11/02 18:48:07 roberto Exp roberto $
** Lua API ** Lua API
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -585,16 +585,16 @@ LUA_API int lua_pushthread (lua_State *L) {
static int auxgetstr (lua_State *L, const TValue *t, const char *k) { static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *aux; const TValue *slot;
TString *str = luaS_new(L, k); TString *str = luaS_new(L, k);
if (luaV_fastget(L, t, str, aux, luaH_getstr)) { if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
setobj2s(L, L->top, aux); setobj2s(L, L->top, slot);
api_incr_top(L); api_incr_top(L);
} }
else { else {
setsvalue2s(L, L->top, str); setsvalue2s(L, L->top, str);
api_incr_top(L); api_incr_top(L);
luaV_finishget(L, t, L->top - 1, L->top - 1, aux); luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
} }
lua_unlock(L); lua_unlock(L);
return ttnov(L->top - 1); return ttnov(L->top - 1);
@ -626,17 +626,17 @@ LUA_API int lua_getfield (lua_State *L, int idx, const char *k) {
LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
StkId t; StkId t;
const TValue *aux; const TValue *slot;
lua_lock(L); lua_lock(L);
t = index2addr(L, idx); t = index2addr(L, idx);
if (luaV_fastget(L, t, n, aux, luaH_getint)) { if (luaV_fastget(L, t, n, slot, luaH_getint)) {
setobj2s(L, L->top, aux); setobj2s(L, L->top, slot);
api_incr_top(L); api_incr_top(L);
} }
else { else {
setivalue(L->top, n); setivalue(L->top, n);
api_incr_top(L); api_incr_top(L);
luaV_finishget(L, t, L->top - 1, L->top - 1, aux); luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
} }
lua_unlock(L); lua_unlock(L);
return ttnov(L->top - 1); return ttnov(L->top - 1);
@ -740,15 +740,15 @@ LUA_API int lua_getuservalue (lua_State *L, int idx) {
** t[k] = value at the top of the stack (where 'k' is a string) ** t[k] = value at the top of the stack (where 'k' is a string)
*/ */
static void auxsetstr (lua_State *L, const TValue *t, const char *k) { static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *aux; const TValue *slot;
TString *str = luaS_new(L, k); TString *str = luaS_new(L, k);
api_checknelems(L, 1); api_checknelems(L, 1);
if (luaV_fastset(L, t, str, aux, luaH_getstr, L->top - 1)) if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1))
L->top--; /* pop value */ L->top--; /* pop value */
else { else {
setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */
api_incr_top(L); api_incr_top(L);
luaV_finishset(L, t, L->top - 1, L->top - 2, aux); luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
L->top -= 2; /* pop value and key */ L->top -= 2; /* pop value and key */
} }
lua_unlock(L); /* lock done by caller */ lua_unlock(L); /* lock done by caller */
@ -781,16 +781,16 @@ LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
StkId t; StkId t;
const TValue *aux; const TValue *slot;
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
t = index2addr(L, idx); t = index2addr(L, idx);
if (luaV_fastset(L, t, n, aux, luaH_getint, L->top - 1)) if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1))
L->top--; /* pop value */ L->top--; /* pop value */
else { else {
setivalue(L->top, n); setivalue(L->top, n);
api_incr_top(L); api_incr_top(L);
luaV_finishset(L, t, L->top - 1, L->top - 2, aux); luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
L->top -= 2; /* pop value and key */ L->top -= 2; /* pop value and key */
} }
lua_unlock(L); lua_unlock(L);

61
lvm.c
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lvm.c,v 2.265 2015/11/23 11:30:45 roberto Exp roberto $ ** $Id: lvm.c,v 2.266 2016/01/04 16:44:50 roberto Exp roberto $
** Lua virtual machine ** Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -153,28 +153,41 @@ static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step,
/* /*
** Finish a table access: if 't' is a table, 'tm' has its metamethod; ** Finish the table access 'val = t[key]'.
** otherwise, 'tm' is NULL. ** 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, void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
const TValue *tm) { const TValue *slot) {
int loop; /* counter to avoid infinite loops */ int loop; /* counter to avoid infinite loops */
lua_assert(tm != NULL || !ttistable(t)); const TValue *tm; /* metamethod */
for (loop = 0; loop < MAXTAGLOOP; loop++) { for (loop = 0; loop < MAXTAGLOOP; loop++) {
if (tm == NULL) { /* no metamethod (from a table)? */ if (slot == NULL) { /* 't' is not a table? */
if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) lua_assert(!ttistable(t));
tm = luaT_gettmbyobj(L, t, TM_INDEX);
if (ttisnil(tm))
luaG_typeerror(L, t, "index"); /* no metamethod */ luaG_typeerror(L, t, "index"); /* no metamethod */
/* else will try the metamethod */
} }
if (ttisfunction(tm)) { /* metamethod is a function */ 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 metamethod */
}
if (ttisfunction(tm)) { /* is metamethod a function? */
luaT_callTM(L, tm, t, key, val, 1); /* call it */ luaT_callTM(L, tm, t, key, val, 1); /* call it */
return; return;
} }
t = tm; /* else repeat access over 'tm' */ t = tm; /* else try to access 'tm[key]' */
if (luaV_fastget(L,t,key,tm,luaH_get)) { /* try fast track */ if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */
setobj2s(L, val, tm); /* done */ setobj2s(L, val, slot); /* done */
return; return;
} }
/* else repeat */ /* else repeat (tail call 'luaV_finishget') */
} }
luaG_runerror(L, "'__index' chain too long; possible loop"); luaG_runerror(L, "'__index' chain too long; possible loop");
} }
@ -182,25 +195,25 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
/* /*
** Finish a table assignment 't[key] = val'. ** Finish a table assignment 't[key] = val'.
** If 'oldval' is NULL, 't' is not a table. Otherwise, 'oldval' points ** 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 ** to the entry 't[key]', or to 'luaO_nilobject' if there is no such
** entry. (The value at 'oldval' must be nil, otherwise 'luaV_fastset' ** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset'
** would have done the job.) ** would have done the job.)
*/ */
void luaV_finishset (lua_State *L, const TValue *t, TValue *key, void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *oldval) { StkId val, const TValue *slot) {
int loop; /* counter to avoid infinite loops */ int loop; /* counter to avoid infinite loops */
for (loop = 0; loop < MAXTAGLOOP; loop++) { for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm; /* '__newindex' metamethod */ const TValue *tm; /* '__newindex' metamethod */
if (oldval != NULL) { /* is 't' a table? */ if (slot != NULL) { /* is 't' a table? */
Table *h = hvalue(t); /* save 't' table */ Table *h = hvalue(t); /* save 't' table */
lua_assert(ttisnil(oldval)); /* old value must be nil */ lua_assert(ttisnil(slot)); /* old value must be nil */
tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */
if (tm == NULL) { /* no metamethod? */ if (tm == NULL) { /* no metamethod? */
if (oldval == luaO_nilobject) /* no previous entry? */ if (slot == luaO_nilobject) /* no previous entry? */
oldval = luaH_newkey(L, h, key); /* create one */ slot = luaH_newkey(L, h, key); /* create one */
/* no metamethod and (now) there is an entry with given key */ /* no metamethod and (now) there is an entry with given key */
setobj2t(L, cast(TValue *, oldval), val); /* set its new value */ setobj2t(L, cast(TValue *, slot), val); /* set its new value */
invalidateTMcache(h); invalidateTMcache(h);
luaC_barrierback(L, h, val); luaC_barrierback(L, h, val);
return; return;
@ -217,7 +230,7 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
return; return;
} }
t = tm; /* else repeat assignment over 'tm' */ t = tm; /* else repeat assignment over 'tm' */
if (luaV_fastset(L, t, key, oldval, luaH_get, val)) if (luaV_fastset(L, t, key, slot, luaH_get, val))
return; /* done */ return; /* done */
/* else loop */ /* else loop */
} }
@ -748,9 +761,9 @@ void luaV_finishOp (lua_State *L) {
** copy of 'luaV_gettable', but protecting the call to potential ** copy of 'luaV_gettable', but protecting the call to potential
** metamethod (which can reallocate the stack) ** metamethod (which can reallocate the stack)
*/ */
#define gettableProtected(L,t,k,v) { const TValue *aux; \ #define gettableProtected(L,t,k,v) { const TValue *slot; \
if (luaV_fastget(L,t,k,aux,luaH_get)) { setobj2s(L, v, aux); } \ if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
else Protect(luaV_finishget(L,t,k,v,aux)); } else Protect(luaV_finishget(L,t,k,v,slot)); }
/* same for 'luaV_settable' */ /* same for 'luaV_settable' */

31
lvm.h
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lvm.h,v 2.38 2015/08/03 20:40:26 roberto Exp roberto $ ** $Id: lvm.h,v 2.39 2015/09/09 13:44:07 roberto Exp roberto $
** Lua virtual machine ** Lua virtual machine
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -49,25 +49,24 @@
/* /*
** fast track for 'gettable': 1 means 'aux' points to resulted value; ** fast track for 'gettable': if 't' is a table and 't[k]' is not nil,
** 0 means 'aux' is metamethod (if 't' is a table) or NULL. 'f' is ** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise,
** the raw get function to use. ** 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,aux,f) \ #define luaV_fastget(L,t,k,slot,f) \
(!ttistable(t) \ (!ttistable(t) \
? (aux = NULL, 0) /* not a table; 'aux' is NULL and result is 0 */ \ ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
: (aux = f(hvalue(t), k), /* else, do raw access */ \ : (slot = f(hvalue(t), k), /* else, do raw access */ \
!ttisnil(aux) ? 1 /* result not nil? 'aux' has it */ \ !ttisnil(slot))) /* result not nil? */
: (aux = fasttm(L, hvalue(t)->metatable, TM_INDEX), /* get metamethod */\
aux != NULL ? 0 /* has metamethod? must call it */ \
: (aux = luaO_nilobject, 1)))) /* else, final result is nil */
/* /*
** standard implementation for 'gettable' ** standard implementation for 'gettable'
*/ */
#define luaV_gettable(L,t,k,v) { const TValue *aux; \ #define luaV_gettable(L,t,k,v) { const TValue *slot; \
if (luaV_fastget(L,t,k,aux,luaH_get)) { setobj2s(L, v, aux); } \ if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
else luaV_finishget(L,t,k,v,aux); } else luaV_finishget(L,t,k,v,slot); }
/* /*
@ -100,9 +99,9 @@ LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n); LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n);
LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode); LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode);
LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *tm); StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *oldval); StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishOp (lua_State *L); LUAI_FUNC void luaV_finishOp (lua_State *L);
LUAI_FUNC void luaV_execute (lua_State *L); LUAI_FUNC void luaV_execute (lua_State *L);
LUAI_FUNC void luaV_concat (lua_State *L, int total); LUAI_FUNC void luaV_concat (lua_State *L, int total);