lua

A copy of the Lua development repository
Log | Files | Refs | README

commit 7647d5d13d016f114dac4be0b9da62d502eab400
parent 7184f6343a0074d02f6f0e35654cfa55427710d3
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date:   Thu, 11 May 2017 15:57:19 -0300

revamp of fast track for table access (table set uses the same
macros as table get + new macro for integer keys)

Diffstat:
Mlapi.c | 41++++++++++++++++++++++++++---------------
Mlvm.c | 87+++++++++++++++++++++++++++++++++----------------------------------------------
Mlvm.h | 47+++++++++++++++++++----------------------------
3 files changed, 81 insertions(+), 94 deletions(-)

diff --git a/lapi.c b/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.264 2017/04/20 18:22:44 roberto Exp roberto $ +** $Id: lapi.c,v 2.265 2017/04/24 16:59:26 roberto Exp roberto $ ** Lua API ** See Copyright Notice in lua.h */ @@ -609,10 +609,15 @@ LUA_API int lua_getglobal (lua_State *L, const char *name) { LUA_API int lua_gettable (lua_State *L, int idx) { + const TValue *slot; StkId t; lua_lock(L); t = index2addr(L, idx); - luaV_gettable(L, t, L->top - 1, L->top - 1); + if (luaV_fastget(L, t, L->top - 1, slot, luaH_get)) { + setobj2s(L, L->top - 1, slot); + } + else + luaV_finishget(L, t, L->top - 1, L->top - 1, slot); lua_unlock(L); return ttnov(L->top - 1); } @@ -629,15 +634,15 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { const TValue *slot; lua_lock(L); t = index2addr(L, idx); - if (luaV_fastget(L, t, n, slot, luaH_getint)) { + if (luaV_fastgeti(L, t, n, slot)) { 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, slot); + TValue aux; + setivalue(&aux, n); + luaV_finishget(L, t, &aux, L->top, slot); } + api_incr_top(L); lua_unlock(L); return ttnov(L->top - 1); } @@ -743,8 +748,10 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) { const TValue *slot; TString *str = luaS_new(L, k); api_checknelems(L, 1); - if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1)) + if (luaV_fastget(L, t, str, slot, luaH_getstr)) { + luaV_finishfastset(L, t, slot, L->top - 1); L->top--; /* pop value */ + } else { setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ api_incr_top(L); @@ -764,10 +771,14 @@ LUA_API void lua_setglobal (lua_State *L, const char *name) { LUA_API void lua_settable (lua_State *L, int idx) { StkId t; + const TValue *slot; lua_lock(L); api_checknelems(L, 2); t = index2addr(L, idx); - luaV_settable(L, t, L->top - 2, L->top - 1); + if (luaV_fastget(L, t, L->top - 2, slot, luaH_get)) + luaV_finishfastset(L, t, slot, L->top - 1); + else + luaV_finishset(L, t, L->top - 2, L->top - 1, slot); L->top -= 2; /* pop index and value */ lua_unlock(L); } @@ -785,14 +796,14 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { lua_lock(L); api_checknelems(L, 1); t = index2addr(L, idx); - if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1)) - L->top--; /* pop value */ + if (luaV_fastgeti(L, t, n, slot)) + luaV_finishfastset(L, t, slot, L->top - 1); else { - setivalue(L->top, n); - api_incr_top(L); - luaV_finishset(L, t, L->top - 1, L->top - 2, slot); - L->top -= 2; /* pop value and key */ + TValue aux; + setivalue(&aux, n); + luaV_finishset(L, t, &aux, L->top - 1, slot); } + L->top--; /* pop value */ lua_unlock(L); } diff --git a/lvm.c b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.278 2017/05/08 16:08:01 roberto Exp roberto $ +** $Id: lvm.c,v 2.279 2017/05/10 17:32:19 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -182,7 +182,7 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, return; } t = tm; /* else try to access 'tm[key]' */ - if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */ + if (luaV_fastget(L, t, key, slot, luaH_get)) { /* fast track? */ setobj2s(L, val, slot); /* done */ return; } @@ -196,7 +196,7 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, ** 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' +** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastget' ** would have done the job.) */ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, @@ -229,9 +229,11 @@ 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, slot, luaH_get, val)) + if (luaV_fastget(L, t, key, slot, luaH_get)) { + luaV_finishfastset(L, t, slot, val); return; /* done */ - /* else loop */ + } + /* else 'return luaV_finishset(L, t, key, val, slot)' (loop) */ } luaG_runerror(L, "'__newindex' chain too long; possible loop"); } @@ -791,35 +793,6 @@ void luaV_finishOp (lua_State *L) { #define vmbreak break -/* -** copy of 'luaV_gettable', but protecting the 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_get,v)) \ - Protect(luaV_finishset(L,t,k,v,slot)); } - - -/* -** Predicate for integer fast track in GET/SETTABLE. -** (Strings are usually constant and therefore coded with -** GET/SETFIELD). Check that index is an integer, "table" is -** a table, index is in the array part, and value is not nil -** (otherwise it will need metamethods). Use 'n' and 't' for -** for caching the integer and table values. -*/ -#define fastintindex(tbl,idx,t,n) \ - (ttisinteger(idx) && ttistable(tbl) && \ - (n = l_castS2U(ivalue(idx)) - 1u, t = hvalue(tbl), \ - n < t->sizearray) && !ttisnil(&t->array[n])) - - void luaV_execute (lua_State *L) { CallInfo *ci = L->ci; LClosure *cl; @@ -899,21 +872,24 @@ void luaV_execute (lua_State *L) { vmbreak; } vmcase(OP_GETTABLE) { + const TValue *slot; StkId rb = RB(i); TValue *rc = RC(i); - Table *t; lua_Unsigned n; - if (fastintindex(rb, rc, t, n)) { - setobj2s(L, ra, &t->array[n]); + lua_Unsigned n; + if (ttisinteger(rc) /* fast track for integers? */ + ? (n = ivalue(rc), luaV_fastgeti(L, rb, n, slot)) + : luaV_fastget(L, rb, rc, slot, luaH_get)) { + setobj2s(L, ra, slot); } else - gettableProtected(L, rb, rc, ra); + Protect(luaV_finishget(L, rb, rc, ra, slot)); vmbreak; } vmcase(OP_GETI) { const TValue *slot; StkId rb = RB(i); int c = GETARG_C(i); - if (luaV_fastget(L, rb, c, slot, luaH_getint)) { + if (luaV_fastgeti(L, rb, c, slot)) { setobj2s(L, ra, slot); } else { @@ -940,26 +916,32 @@ void luaV_execute (lua_State *L) { TValue *rb = KB(i); TValue *rc = RKC(i); TString *key = tsvalue(rb); /* key must be a string */ - if (!luaV_fastset(L, upval, key, slot, luaH_getstr, rc)) + if (luaV_fastget(L, upval, key, slot, luaH_getstr)) + luaV_finishfastset(L, upval, slot, rc); + else Protect(luaV_finishset(L, upval, rb, rc, slot)); vmbreak; } vmcase(OP_SETTABLE) { - TValue *rb = RB(i); - TValue *rc = RKC(i); - Table *t; lua_Unsigned n; - if (fastintindex(ra, rb, t, n)) { - setobj2t(L, &t->array[n], rc); - } + const TValue *slot; + TValue *rb = RB(i); /* key (table is in 'ra') */ + TValue *rc = RKC(i); /* value */ + lua_Unsigned n; + if (ttisinteger(rb) /* fast track for integers? */ + ? (n = ivalue(rb), luaV_fastgeti(L, ra, n, slot)) + : luaV_fastget(L, ra, rb, slot, luaH_get)) + luaV_finishfastset(L, ra, slot, rc); else - settableProtected(L, ra, rb, rc); + Protect(luaV_finishset(L, ra, rb, rc, slot)); vmbreak; } vmcase(OP_SETI) { const TValue *slot; int c = GETARG_B(i); TValue *rc = RKC(i); - if (!luaV_fastset(L, ra, c, slot, luaH_getint, rc)) { + if (luaV_fastgeti(L, ra, c, slot)) + luaV_finishfastset(L, ra, slot, rc); + else { TValue key; setivalue(&key, c); Protect(luaV_finishset(L, ra, &key, rc, slot)); @@ -971,7 +953,9 @@ void luaV_execute (lua_State *L) { TValue *rb = KB(i); TValue *rc = RKC(i); TString *key = tsvalue(rb); /* key must be a string */ - if (!luaV_fastset(L, ra, key, slot, luaH_getstr, rc)) + if (luaV_fastget(L, ra, key, slot, luaH_getstr)) + luaV_finishfastset(L, ra, slot, rc); + else Protect(luaV_finishset(L, ra, rb, rc, slot)); vmbreak; } @@ -1427,8 +1411,9 @@ void luaV_execute (lua_State *L) { if (last > h->sizearray) /* needs more space? */ luaH_resizearray(L, h, last); /* preallocate it at once */ for (; n > 0; n--) { - TValue *val = ra+n; - luaH_setint(L, h, last--, val); + TValue *val = ra + n; + setobj2t(L, &h->array[last - 1], val); + last--; luaC_barrierback(L, h, val); } L->top = ci->top; /* correct top (in case of previous open call) */ diff --git a/lvm.h b/lvm.h @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 2.40 2016/01/05 16:07:21 roberto Exp roberto $ +** $Id: lvm.h,v 2.41 2016/12/22 13:08:50 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -50,10 +50,10 @@ /* ** 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. +** return 1 with 'slot' pointing to 't[k]' (position of 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) \ @@ -61,35 +61,26 @@ : (slot = f(hvalue(t), k), /* else, do raw access */ \ !ttisnil(slot))) /* result not nil? */ + /* -** standard implementation for 'gettable' +** Special case of 'luaV_fastget' for integers, inlining the fast case +** of 'luaH_getint'. */ -#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); } +#define luaV_fastgeti(L,t,k,slot) \ + (!ttistable(t) \ + ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ + : (slot = (l_castS2U(k) - 1u < hvalue(t)->sizearray) \ + ? &hvalue(t)->array[k - 1] : luaH_getint(hvalue(t), k), \ + !ttisnil(slot))) /* result not nil? */ /* -** 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. +** Finish a fast set operation (when fast get succeeds). In that case, +** 'slot' points to the place to put the value. */ -#define luaV_fastset(L,t,k,slot,f,v) \ - (!ttistable(t) \ - ? (slot = NULL, 0) \ - : (slot = f(hvalue(t), k), \ - ttisnil(slot) ? 0 \ - : (luaC_barrierback(L, hvalue(t), v), \ - 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_get,v)) \ - luaV_finishset(L,t,k,v,slot); } +#define luaV_finishfastset(L,t,slot,v) \ + (setobj2t(L, cast(TValue *,slot), v), luaC_barrierback(L, hvalue(t), v)) +