Optimizations for 'lua_rawgeti' and 'lua_rawseti'
'lua_rawgeti' now uses "fast track"; 'lua_rawseti' still calls 'luaH_setint', but the latter was recoded to avoid extra overhead when writing to the array part after 'alimit'.
This commit is contained in:
19
lapi.c
19
lapi.c
@@ -102,7 +102,7 @@ static TValue *index2value (lua_State *L, int idx) {
|
|||||||
/*
|
/*
|
||||||
** Convert a valid actual index (not a pseudo-index) to its address.
|
** Convert a valid actual index (not a pseudo-index) to its address.
|
||||||
*/
|
*/
|
||||||
l_sinline StkId index2stack (lua_State *L, int idx) {
|
static StkId index2stack (lua_State *L, int idx) {
|
||||||
CallInfo *ci = L->ci;
|
CallInfo *ci = L->ci;
|
||||||
if (idx > 0) {
|
if (idx > 0) {
|
||||||
StkId o = ci->func.p + idx;
|
StkId o = ci->func.p + idx;
|
||||||
@@ -234,7 +234,7 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
|
|||||||
** Note that we move(copy) only the value inside the stack.
|
** Note that we move(copy) only the value inside the stack.
|
||||||
** (We do not move additional fields that may exist.)
|
** (We do not move additional fields that may exist.)
|
||||||
*/
|
*/
|
||||||
l_sinline void reverse (lua_State *L, StkId from, StkId to) {
|
static void reverse (lua_State *L, StkId from, StkId to) {
|
||||||
for (; from < to; from++, to--) {
|
for (; from < to; from++, to--) {
|
||||||
TValue temp;
|
TValue temp;
|
||||||
setobj(L, &temp, s2v(from));
|
setobj(L, &temp, s2v(from));
|
||||||
@@ -664,7 +664,7 @@ LUA_API int lua_pushthread (lua_State *L) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) {
|
static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
|
||||||
int hres;
|
int hres;
|
||||||
TString *str = luaS_new(L, k);
|
TString *str = luaS_new(L, k);
|
||||||
luaV_fastget(t, str, s2v(L->top.p), luaH_getstr, hres);
|
luaV_fastget(t, str, s2v(L->top.p), luaH_getstr, hres);
|
||||||
@@ -683,7 +683,9 @@ l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) {
|
|||||||
|
|
||||||
static void getGlobalTable (lua_State *L, TValue *gt) {
|
static void getGlobalTable (lua_State *L, TValue *gt) {
|
||||||
Table *registry = hvalue(&G(L)->l_registry);
|
Table *registry = hvalue(&G(L)->l_registry);
|
||||||
luaH_getint(registry, LUA_RIDX_GLOBALS, gt);
|
int hres = luaH_getint(registry, LUA_RIDX_GLOBALS, gt);
|
||||||
|
(void)hres; /* avoid warnings (not used) when checks are off */
|
||||||
|
api_check(L, hres == HOK, "global table must exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -740,7 +742,7 @@ l_sinline int finishrawget (lua_State *L, int hres) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Table *gettable (lua_State *L, int idx) {
|
l_sinline Table *gettable (lua_State *L, int idx) {
|
||||||
TValue *t = index2value(L, idx);
|
TValue *t = index2value(L, idx);
|
||||||
api_check(L, ttistable(t), "table expected");
|
api_check(L, ttistable(t), "table expected");
|
||||||
return hvalue(t);
|
return hvalue(t);
|
||||||
@@ -761,9 +763,11 @@ LUA_API int lua_rawget (lua_State *L, int idx) {
|
|||||||
|
|
||||||
LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) {
|
LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) {
|
||||||
Table *t;
|
Table *t;
|
||||||
|
int hres;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
t = gettable(L, idx);
|
t = gettable(L, idx);
|
||||||
return finishrawget(L, luaH_getint(t, n, s2v(L->top.p)));
|
luaH_fastgeti(t, n, s2v(L->top.p), hres);
|
||||||
|
return finishrawget(L, hres);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -901,9 +905,8 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
|
|||||||
api_checknelems(L, 1);
|
api_checknelems(L, 1);
|
||||||
t = index2value(L, idx);
|
t = index2value(L, idx);
|
||||||
luaV_fastseti(t, n, s2v(L->top.p - 1), hres);
|
luaV_fastseti(t, n, s2v(L->top.p - 1), hres);
|
||||||
if (hres == HOK) {
|
if (hres == HOK)
|
||||||
luaV_finishfastset(L, t, s2v(L->top.p - 1));
|
luaV_finishfastset(L, t, s2v(L->top.p - 1));
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
TValue temp;
|
TValue temp;
|
||||||
setivalue(&temp, n);
|
setivalue(&temp, n);
|
||||||
|
|||||||
55
ltable.c
55
ltable.c
@@ -408,21 +408,22 @@ static void freehash (lua_State *L, Table *t) {
|
|||||||
** not the real size of the array, the key still can be in the array
|
** not the real size of the array, the key still can be in the array
|
||||||
** part. In this case, do the "Xmilia trick" to check whether 'key-1'
|
** part. In this case, do the "Xmilia trick" to check whether 'key-1'
|
||||||
** is smaller than the real size.
|
** is smaller than the real size.
|
||||||
** The trick works as follow: let 'p' be an integer such that
|
** The trick works as follow: let 'p' be the integer such that
|
||||||
** '2^(p+1) >= alimit > 2^p', or '2^(p+1) > alimit-1 >= 2^p'.
|
** '2^(p+1) >= alimit > 2^p', or '2^(p+1) > alimit-1 >= 2^p'. That is,
|
||||||
** That is, 2^(p+1) is the real size of the array, and 'p' is the highest
|
** 'p' is the highest 1-bit in 'alimit-1', and 2^(p+1) is the real size
|
||||||
** bit on in 'alimit-1'. What we have to check becomes 'key-1 < 2^(p+1)'.
|
** of the array. What we have to check becomes 'key-1 < 2^(p+1)'. We
|
||||||
** We compute '(key-1) & ~(alimit-1)', which we call 'res'; it will
|
** compute '(key-1) & ~(alimit-1)', which we call 'res'; it will have
|
||||||
** have the 'p' bit cleared. If the key is outside the array, that is,
|
** the 'p' bit cleared. (It may also clear other bits smaller than 'p',
|
||||||
** 'key-1 >= 2^(p+1)', then 'res' will have some 1-bit higher than 'p',
|
** but no bit higher than 'p'.) If the key is outside the array, that
|
||||||
** therefore it will be larger or equal to 'alimit', and the check
|
** is, 'key-1 >= 2^(p+1)', then 'res' will have some 1-bit higher than
|
||||||
|
** 'p', therefore it will be larger or equal to 'alimit', and the check
|
||||||
** will fail. If 'key-1 < 2^(p+1)', then 'res' has no 1-bit higher than
|
** will fail. If 'key-1 < 2^(p+1)', then 'res' has no 1-bit higher than
|
||||||
** 'p', and as the bit 'p' itself was cleared, 'res' will be smaller
|
** 'p', and as the bit 'p' itself was cleared, 'res' will be smaller
|
||||||
** than 2^p, therefore smaller than 'alimit', and the check succeeds.
|
** than 2^p, therefore smaller than 'alimit', and the check succeeds.
|
||||||
** As special cases, when 'alimit' is 0 the condition is trivially false,
|
** As special cases, when 'alimit' is 0 the condition is trivially false,
|
||||||
** and when 'alimit' is 1 the condition simplifies to 'key-1 < alimit'.
|
** and when 'alimit' is 1 the condition simplifies to 'key-1 < alimit'.
|
||||||
** If key is 0 or negative, 'res' will have its higher bit on, so that
|
** If key is 0 or negative, 'res' will have its higher bit on, so that
|
||||||
** if cannot be smaller than alimit.
|
** it cannot be smaller than 'alimit'.
|
||||||
*/
|
*/
|
||||||
static int keyinarray (Table *t, lua_Integer key) {
|
static int keyinarray (Table *t, lua_Integer key) {
|
||||||
lua_Unsigned alimit = t->alimit;
|
lua_Unsigned alimit = t->alimit;
|
||||||
@@ -788,11 +789,11 @@ static Node *getfreepos (Table *t) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** inserts a new key into a hash table; first, check whether key's main
|
** Inserts a new key into a hash table; first, check whether key's main
|
||||||
** position is free. If not, check whether colliding node is in its main
|
** position is free. If not, check whether colliding node is in its main
|
||||||
** position or not: if it is not, move colliding node to an empty place and
|
** position or not: if it is not, move colliding node to an empty place
|
||||||
** put new key in its main position; otherwise (colliding node is in its main
|
** and put new key in its main position; otherwise (colliding node is in
|
||||||
** position), new key goes to an empty position.
|
** its main position), new key goes to an empty position.
|
||||||
*/
|
*/
|
||||||
static void luaH_newkey (lua_State *L, Table *t, const TValue *key,
|
static void luaH_newkey (lua_State *L, Table *t, const TValue *key,
|
||||||
TValue *value) {
|
TValue *value) {
|
||||||
@@ -987,6 +988,16 @@ static int finishnodeset (Table *t, const TValue *slot, TValue *val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int rawfinishnodeset (const TValue *slot, TValue *val) {
|
||||||
|
if (isabstkey(slot))
|
||||||
|
return 0; /* no slot with that key */
|
||||||
|
else {
|
||||||
|
setobj(((lua_State*)NULL), cast(TValue*, slot), val);
|
||||||
|
return 1; /* success */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int luaH_psetint (Table *t, lua_Integer key, TValue *val) {
|
int luaH_psetint (Table *t, lua_Integer key, TValue *val) {
|
||||||
if (keyinarray(t, key)) {
|
if (keyinarray(t, key)) {
|
||||||
lu_byte *tag = getArrTag(t, key - 1);
|
lu_byte *tag = getArrTag(t, key - 1);
|
||||||
@@ -1063,12 +1074,20 @@ void luaH_set (lua_State *L, Table *t, const TValue *key, TValue *value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Ditto for a GC barrier. (No need to invalidate the TM cache, as
|
||||||
|
** integers cannot be keys to metamethods.)
|
||||||
|
*/
|
||||||
void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) {
|
void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) {
|
||||||
int hres = luaH_psetint(t, key, value);
|
if (keyinarray(t, key))
|
||||||
if (hres != HOK) {
|
obj2arr(t, key, value);
|
||||||
TValue k;
|
else {
|
||||||
setivalue(&k, key);
|
int ok = rawfinishnodeset(getintfromhash(t, key), value);
|
||||||
luaH_finishset(L, t, &k, value, hres);
|
if (!ok) {
|
||||||
|
TValue k;
|
||||||
|
setivalue(&k, key);
|
||||||
|
luaH_newkey(L, t, &k, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
19
ltable.h
19
ltable.h
@@ -45,6 +45,25 @@
|
|||||||
#define nodefromval(v) cast(Node *, (v))
|
#define nodefromval(v) cast(Node *, (v))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define luaH_fastgeti(t,k,res,hres) \
|
||||||
|
{ Table *h = t; lua_Unsigned u = l_castS2U(k); \
|
||||||
|
if ((u - 1u < h->alimit)) { \
|
||||||
|
int tag = *getArrTag(h,(u)-1u); \
|
||||||
|
if (tagisempty(tag)) hres = HNOTFOUND; \
|
||||||
|
else { farr2val(h, u, tag, res); hres = HOK; }} \
|
||||||
|
else { hres = luaH_getint(h, u, res); }}
|
||||||
|
|
||||||
|
|
||||||
|
#define luaH_fastseti(t,k,val,hres) \
|
||||||
|
{ Table *h = t; lua_Unsigned u = l_castS2U(k); \
|
||||||
|
if ((u - 1u < h->alimit)) { \
|
||||||
|
lu_byte *tag = getArrTag(h,(u)-1u); \
|
||||||
|
if (tagisempty(*tag)) hres = ~cast_int(u); \
|
||||||
|
else { fval2arr(h, u, tag, val); hres = HOK; }} \
|
||||||
|
else { hres = luaH_psetint(h, u, val); }}
|
||||||
|
|
||||||
|
|
||||||
/* results from get/pset */
|
/* results from get/pset */
|
||||||
#define HOK 0
|
#define HOK 0
|
||||||
#define HNOTFOUND 1
|
#define HNOTFOUND 1
|
||||||
|
|||||||
30
lvm.h
30
lvm.h
@@ -78,35 +78,25 @@ typedef enum {
|
|||||||
/*
|
/*
|
||||||
** fast track for 'gettable'
|
** fast track for 'gettable'
|
||||||
*/
|
*/
|
||||||
#define luaV_fastget(t,k,res,f, aux) \
|
#define luaV_fastget(t,k,res,f, hres) \
|
||||||
(aux = (!ttistable(t) ? HNOTATABLE : f(hvalue(t), k, res)))
|
(hres = (!ttistable(t) ? HNOTATABLE : f(hvalue(t), k, res)))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Special case of 'luaV_fastget' for integers, inlining the fast case
|
** Special case of 'luaV_fastget' for integers, inlining the fast case
|
||||||
** of 'luaH_getint'.
|
** of 'luaH_getint'.
|
||||||
*/
|
*/
|
||||||
#define luaV_fastgeti(t,k,res,aux) \
|
#define luaV_fastgeti(t,k,res,hres) \
|
||||||
if (!ttistable(t)) aux = HNOTATABLE; \
|
if (!ttistable(t)) hres = HNOTATABLE; \
|
||||||
else { Table *h = hvalue(t); lua_Unsigned u = l_castS2U(k); \
|
else { luaH_fastgeti(hvalue(t), k, res, hres); }
|
||||||
if ((u - 1u < h->alimit)) { \
|
|
||||||
int tag = *getArrTag(h,(u)-1u); \
|
|
||||||
if (tagisempty(tag)) aux = HNOTFOUND; \
|
|
||||||
else { farr2val(h, u, tag, res); aux = HOK; }} \
|
|
||||||
else { aux = luaH_getint(h, u, res); }}
|
|
||||||
|
|
||||||
|
|
||||||
#define luaV_fastset(t,k,val,aux,f) \
|
#define luaV_fastset(t,k,val,hres,f) \
|
||||||
(aux = (!ttistable(t) ? HNOTATABLE : f(hvalue(t), k, val)))
|
(hres = (!ttistable(t) ? HNOTATABLE : f(hvalue(t), k, val)))
|
||||||
|
|
||||||
#define luaV_fastseti(t,k,val,aux) \
|
#define luaV_fastseti(t,k,val,hres) \
|
||||||
if (!ttistable(t)) aux = HNOTATABLE; \
|
if (!ttistable(t)) hres = HNOTATABLE; \
|
||||||
else { Table *h = hvalue(t); lua_Unsigned u = l_castS2U(k); \
|
else { luaH_fastseti(hvalue(t), k, val, hres); }
|
||||||
if ((u - 1u < h->alimit)) { \
|
|
||||||
lu_byte *tag = getArrTag(h,(u)-1u); \
|
|
||||||
if (tagisempty(*tag)) aux = ~cast_int(u); \
|
|
||||||
else { fval2arr(h, u, tag, val); aux = HOK; }} \
|
|
||||||
else { aux = luaH_psetint(h, u, val); }}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user