commit 1a44e822009752513ce895b9eabc51a4ee4a195a
parent a272fa66f0c149689e2a2c896434967b7248a0eb
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Tue, 5 Jan 2016 14:06:55 -0200
'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)
Diffstat:
M | lapi.c | | | 30 | +++++++++++++++--------------- |
M | lvm.c | | | 61 | +++++++++++++++++++++++++++++++++++++------------------------ |
M | lvm.h | | | 31 | +++++++++++++++---------------- |
3 files changed, 67 insertions(+), 55 deletions(-)
diff --git a/lapi.c b/lapi.c
@@ -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
** 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) {
- const TValue *aux;
+ const TValue *slot;
TString *str = luaS_new(L, k);
- if (luaV_fastget(L, t, str, aux, luaH_getstr)) {
- setobj2s(L, L->top, aux);
+ if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
+ setobj2s(L, L->top, slot);
api_incr_top(L);
}
else {
setsvalue2s(L, L->top, str);
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);
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) {
StkId t;
- const TValue *aux;
+ const TValue *slot;
lua_lock(L);
t = index2addr(L, idx);
- if (luaV_fastget(L, t, n, aux, luaH_getint)) {
- setobj2s(L, L->top, aux);
+ if (luaV_fastget(L, t, n, slot, luaH_getint)) {
+ setobj2s(L, L->top, slot);
api_incr_top(L);
}
else {
setivalue(L->top, n);
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);
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)
*/
static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
- const TValue *aux;
+ const TValue *slot;
TString *str = luaS_new(L, k);
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 */
else {
setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */
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 */
}
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) {
StkId t;
- const TValue *aux;
+ const TValue *slot;
lua_lock(L);
api_checknelems(L, 1);
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 */
else {
setivalue(L->top, n);
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 */
}
lua_unlock(L);
diff --git a/lvm.c b/lvm.c
@@ -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
** 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;
-** otherwise, 'tm' is NULL.
+** 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 *tm) {
+ const TValue *slot) {
int loop; /* counter to avoid infinite loops */
- lua_assert(tm != NULL || !ttistable(t));
+ const TValue *tm; /* metamethod */
for (loop = 0; loop < MAXTAGLOOP; loop++) {
- if (tm == NULL) { /* no metamethod (from a table)? */
- if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX)))
+ if (slot == NULL) { /* 't' is not a table? */
+ lua_assert(!ttistable(t));
+ tm = luaT_gettmbyobj(L, t, TM_INDEX);
+ if (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 metamethod */
}
- if (ttisfunction(tm)) { /* metamethod is a function */
+ if (ttisfunction(tm)) { /* is metamethod a function? */
luaT_callTM(L, tm, t, key, val, 1); /* call it */
return;
}
- t = tm; /* else repeat access over 'tm' */
- if (luaV_fastget(L,t,key,tm,luaH_get)) { /* try fast track */
- setobj2s(L, val, tm); /* done */
+ 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 */
+ /* else repeat (tail call 'luaV_finishget') */
}
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'.
-** 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
-** 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.)
*/
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 */
for (loop = 0; loop < MAXTAGLOOP; loop++) {
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 */
- 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 */
if (tm == NULL) { /* no metamethod? */
- if (oldval == luaO_nilobject) /* no previous entry? */
- oldval = luaH_newkey(L, h, key); /* create one */
+ if (slot == luaO_nilobject) /* no previous entry? */
+ slot = luaH_newkey(L, h, key); /* create one */
/* 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);
luaC_barrierback(L, h, val);
return;
@@ -217,7 +230,7 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
return;
}
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 */
/* else loop */
}
@@ -748,9 +761,9 @@ void luaV_finishOp (lua_State *L) {
** copy of 'luaV_gettable', but protecting the call to potential
** metamethod (which can reallocate the stack)
*/
-#define gettableProtected(L,t,k,v) { const TValue *aux; \
- if (luaV_fastget(L,t,k,aux,luaH_get)) { setobj2s(L, v, aux); } \
- else Protect(luaV_finishget(L,t,k,v,aux)); }
+#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' */
diff --git a/lvm.h b/lvm.h
@@ -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
** See Copyright Notice in lua.h
*/
@@ -49,25 +49,24 @@
/*
-** fast track for 'gettable': 1 means 'aux' points to resulted value;
-** 0 means 'aux' is metamethod (if 't' is a table) or NULL. 'f' is
-** the raw get function to use.
+** 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,aux,f) \
+#define luaV_fastget(L,t,k,slot,f) \
(!ttistable(t) \
- ? (aux = NULL, 0) /* not a table; 'aux' is NULL and result is 0 */ \
- : (aux = f(hvalue(t), k), /* else, do raw access */ \
- !ttisnil(aux) ? 1 /* result not nil? 'aux' has it */ \
- : (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 */
+ ? (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 *aux; \
- if (luaV_fastget(L,t,k,aux,luaH_get)) { setobj2s(L, v, aux); } \
- else luaV_finishget(L,t,k,v,aux); }
+#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); }
/*
@@ -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_tointeger (const TValue *obj, lua_Integer *p, int mode);
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,
- StkId val, const TValue *oldval);
+ StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishOp (lua_State *L);
LUAI_FUNC void luaV_execute (lua_State *L);
LUAI_FUNC void luaV_concat (lua_State *L, int total);