diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2016-01-05 14:07:21 -0200 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2016-01-05 14:07:21 -0200 |
| commit | 1a44e822009752513ce895b9eabc51a4ee4a195a (patch) | |
| tree | dc8c1dc1ca01601335e447d3d627b4354247a31d | |
| parent | a272fa66f0c149689e2a2c896434967b7248a0eb (diff) | |
| download | lua-1a44e822009752513ce895b9eabc51a4ee4a195a.tar.gz lua-1a44e822009752513ce895b9eabc51a4ee4a195a.tar.bz2 lua-1a44e822009752513ce895b9eabc51a4ee4a195a.zip | |
'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)
| -rw-r--r-- | lapi.c | 30 | ||||
| -rw-r--r-- | lvm.c | 61 | ||||
| -rw-r--r-- | lvm.h | 31 |
3 files changed, 67 insertions, 55 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lapi.c,v 2.256 2015/10/06 16:10:22 roberto Exp roberto $ | 2 | ** $Id: lapi.c,v 2.257 2015/11/02 18:48:07 roberto Exp roberto $ |
| 3 | ** Lua API | 3 | ** Lua API |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -585,16 +585,16 @@ LUA_API int lua_pushthread (lua_State *L) { | |||
| 585 | 585 | ||
| 586 | 586 | ||
| 587 | static int auxgetstr (lua_State *L, const TValue *t, const char *k) { | 587 | static int auxgetstr (lua_State *L, const TValue *t, const char *k) { |
| 588 | const TValue *aux; | 588 | const TValue *slot; |
| 589 | TString *str = luaS_new(L, k); | 589 | TString *str = luaS_new(L, k); |
| 590 | if (luaV_fastget(L, t, str, aux, luaH_getstr)) { | 590 | if (luaV_fastget(L, t, str, slot, luaH_getstr)) { |
| 591 | setobj2s(L, L->top, aux); | 591 | setobj2s(L, L->top, slot); |
| 592 | api_incr_top(L); | 592 | api_incr_top(L); |
| 593 | } | 593 | } |
| 594 | else { | 594 | else { |
| 595 | setsvalue2s(L, L->top, str); | 595 | setsvalue2s(L, L->top, str); |
| 596 | api_incr_top(L); | 596 | api_incr_top(L); |
| 597 | luaV_finishget(L, t, L->top - 1, L->top - 1, aux); | 597 | luaV_finishget(L, t, L->top - 1, L->top - 1, slot); |
| 598 | } | 598 | } |
| 599 | lua_unlock(L); | 599 | lua_unlock(L); |
| 600 | return ttnov(L->top - 1); | 600 | return ttnov(L->top - 1); |
| @@ -626,17 +626,17 @@ LUA_API int lua_getfield (lua_State *L, int idx, const char *k) { | |||
| 626 | 626 | ||
| 627 | LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { | 627 | LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { |
| 628 | StkId t; | 628 | StkId t; |
| 629 | const TValue *aux; | 629 | const TValue *slot; |
| 630 | lua_lock(L); | 630 | lua_lock(L); |
| 631 | t = index2addr(L, idx); | 631 | t = index2addr(L, idx); |
| 632 | if (luaV_fastget(L, t, n, aux, luaH_getint)) { | 632 | if (luaV_fastget(L, t, n, slot, luaH_getint)) { |
| 633 | setobj2s(L, L->top, aux); | 633 | setobj2s(L, L->top, slot); |
| 634 | api_incr_top(L); | 634 | api_incr_top(L); |
| 635 | } | 635 | } |
| 636 | else { | 636 | else { |
| 637 | setivalue(L->top, n); | 637 | setivalue(L->top, n); |
| 638 | api_incr_top(L); | 638 | api_incr_top(L); |
| 639 | luaV_finishget(L, t, L->top - 1, L->top - 1, aux); | 639 | luaV_finishget(L, t, L->top - 1, L->top - 1, slot); |
| 640 | } | 640 | } |
| 641 | lua_unlock(L); | 641 | lua_unlock(L); |
| 642 | return ttnov(L->top - 1); | 642 | return ttnov(L->top - 1); |
| @@ -740,15 +740,15 @@ LUA_API int lua_getuservalue (lua_State *L, int idx) { | |||
| 740 | ** t[k] = value at the top of the stack (where 'k' is a string) | 740 | ** t[k] = value at the top of the stack (where 'k' is a string) |
| 741 | */ | 741 | */ |
| 742 | static void auxsetstr (lua_State *L, const TValue *t, const char *k) { | 742 | static void auxsetstr (lua_State *L, const TValue *t, const char *k) { |
| 743 | const TValue *aux; | 743 | const TValue *slot; |
| 744 | TString *str = luaS_new(L, k); | 744 | TString *str = luaS_new(L, k); |
| 745 | api_checknelems(L, 1); | 745 | api_checknelems(L, 1); |
| 746 | if (luaV_fastset(L, t, str, aux, luaH_getstr, L->top - 1)) | 746 | if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1)) |
| 747 | L->top--; /* pop value */ | 747 | L->top--; /* pop value */ |
| 748 | else { | 748 | else { |
| 749 | setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ | 749 | setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ |
| 750 | api_incr_top(L); | 750 | api_incr_top(L); |
| 751 | luaV_finishset(L, t, L->top - 1, L->top - 2, aux); | 751 | luaV_finishset(L, t, L->top - 1, L->top - 2, slot); |
| 752 | L->top -= 2; /* pop value and key */ | 752 | L->top -= 2; /* pop value and key */ |
| 753 | } | 753 | } |
| 754 | lua_unlock(L); /* lock done by caller */ | 754 | lua_unlock(L); /* lock done by caller */ |
| @@ -781,16 +781,16 @@ LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { | |||
| 781 | 781 | ||
| 782 | LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { | 782 | LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { |
| 783 | StkId t; | 783 | StkId t; |
| 784 | const TValue *aux; | 784 | const TValue *slot; |
| 785 | lua_lock(L); | 785 | lua_lock(L); |
| 786 | api_checknelems(L, 1); | 786 | api_checknelems(L, 1); |
| 787 | t = index2addr(L, idx); | 787 | t = index2addr(L, idx); |
| 788 | if (luaV_fastset(L, t, n, aux, luaH_getint, L->top - 1)) | 788 | if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1)) |
| 789 | L->top--; /* pop value */ | 789 | L->top--; /* pop value */ |
| 790 | else { | 790 | else { |
| 791 | setivalue(L->top, n); | 791 | setivalue(L->top, n); |
| 792 | api_incr_top(L); | 792 | api_incr_top(L); |
| 793 | luaV_finishset(L, t, L->top - 1, L->top - 2, aux); | 793 | luaV_finishset(L, t, L->top - 1, L->top - 2, slot); |
| 794 | L->top -= 2; /* pop value and key */ | 794 | L->top -= 2; /* pop value and key */ |
| 795 | } | 795 | } |
| 796 | lua_unlock(L); | 796 | lua_unlock(L); |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lvm.c,v 2.265 2015/11/23 11:30:45 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 2.266 2016/01/04 16:44:50 roberto Exp roberto $ |
| 3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -153,28 +153,41 @@ static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step, | |||
| 153 | 153 | ||
| 154 | 154 | ||
| 155 | /* | 155 | /* |
| 156 | ** Finish a table access: if 't' is a table, 'tm' has its metamethod; | 156 | ** Finish the table access 'val = t[key]'. |
| 157 | ** otherwise, 'tm' is NULL. | 157 | ** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to |
| 158 | ** t[k] entry (which must be nil). | ||
| 158 | */ | 159 | */ |
| 159 | void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, | 160 | void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, |
| 160 | const TValue *tm) { | 161 | const TValue *slot) { |
| 161 | int loop; /* counter to avoid infinite loops */ | 162 | int loop; /* counter to avoid infinite loops */ |
| 162 | lua_assert(tm != NULL || !ttistable(t)); | 163 | const TValue *tm; /* metamethod */ |
| 163 | for (loop = 0; loop < MAXTAGLOOP; loop++) { | 164 | for (loop = 0; loop < MAXTAGLOOP; loop++) { |
| 164 | if (tm == NULL) { /* no metamethod (from a table)? */ | 165 | if (slot == NULL) { /* 't' is not a table? */ |
| 165 | if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) | 166 | lua_assert(!ttistable(t)); |
| 167 | tm = luaT_gettmbyobj(L, t, TM_INDEX); | ||
| 168 | if (ttisnil(tm)) | ||
| 166 | luaG_typeerror(L, t, "index"); /* no metamethod */ | 169 | luaG_typeerror(L, t, "index"); /* no metamethod */ |
| 170 | /* else will try the metamethod */ | ||
| 171 | } | ||
| 172 | else { /* 't' is a table */ | ||
| 173 | lua_assert(ttisnil(slot)); | ||
| 174 | tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */ | ||
| 175 | if (tm == NULL) { /* no metamethod? */ | ||
| 176 | setnilvalue(val); /* result is nil */ | ||
| 177 | return; | ||
| 178 | } | ||
| 179 | /* else will try the metamethod */ | ||
| 167 | } | 180 | } |
| 168 | if (ttisfunction(tm)) { /* metamethod is a function */ | 181 | if (ttisfunction(tm)) { /* is metamethod a function? */ |
| 169 | luaT_callTM(L, tm, t, key, val, 1); /* call it */ | 182 | luaT_callTM(L, tm, t, key, val, 1); /* call it */ |
| 170 | return; | 183 | return; |
| 171 | } | 184 | } |
| 172 | t = tm; /* else repeat access over 'tm' */ | 185 | t = tm; /* else try to access 'tm[key]' */ |
| 173 | if (luaV_fastget(L,t,key,tm,luaH_get)) { /* try fast track */ | 186 | if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */ |
| 174 | setobj2s(L, val, tm); /* done */ | 187 | setobj2s(L, val, slot); /* done */ |
| 175 | return; | 188 | return; |
| 176 | } | 189 | } |
| 177 | /* else repeat */ | 190 | /* else repeat (tail call 'luaV_finishget') */ |
| 178 | } | 191 | } |
| 179 | luaG_runerror(L, "'__index' chain too long; possible loop"); | 192 | luaG_runerror(L, "'__index' chain too long; possible loop"); |
| 180 | } | 193 | } |
| @@ -182,25 +195,25 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, | |||
| 182 | 195 | ||
| 183 | /* | 196 | /* |
| 184 | ** Finish a table assignment 't[key] = val'. | 197 | ** Finish a table assignment 't[key] = val'. |
| 185 | ** If 'oldval' is NULL, 't' is not a table. Otherwise, 'oldval' points | 198 | ** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points |
| 186 | ** to the entry 't[key]', or to 'luaO_nilobject' if there is no such | 199 | ** to the entry 't[key]', or to 'luaO_nilobject' if there is no such |
| 187 | ** entry. (The value at 'oldval' must be nil, otherwise 'luaV_fastset' | 200 | ** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset' |
| 188 | ** would have done the job.) | 201 | ** would have done the job.) |
| 189 | */ | 202 | */ |
| 190 | void luaV_finishset (lua_State *L, const TValue *t, TValue *key, | 203 | void luaV_finishset (lua_State *L, const TValue *t, TValue *key, |
| 191 | StkId val, const TValue *oldval) { | 204 | StkId val, const TValue *slot) { |
| 192 | int loop; /* counter to avoid infinite loops */ | 205 | int loop; /* counter to avoid infinite loops */ |
| 193 | for (loop = 0; loop < MAXTAGLOOP; loop++) { | 206 | for (loop = 0; loop < MAXTAGLOOP; loop++) { |
| 194 | const TValue *tm; /* '__newindex' metamethod */ | 207 | const TValue *tm; /* '__newindex' metamethod */ |
| 195 | if (oldval != NULL) { /* is 't' a table? */ | 208 | if (slot != NULL) { /* is 't' a table? */ |
| 196 | Table *h = hvalue(t); /* save 't' table */ | 209 | Table *h = hvalue(t); /* save 't' table */ |
| 197 | lua_assert(ttisnil(oldval)); /* old value must be nil */ | 210 | lua_assert(ttisnil(slot)); /* old value must be nil */ |
| 198 | tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ | 211 | tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ |
| 199 | if (tm == NULL) { /* no metamethod? */ | 212 | if (tm == NULL) { /* no metamethod? */ |
| 200 | if (oldval == luaO_nilobject) /* no previous entry? */ | 213 | if (slot == luaO_nilobject) /* no previous entry? */ |
| 201 | oldval = luaH_newkey(L, h, key); /* create one */ | 214 | slot = luaH_newkey(L, h, key); /* create one */ |
| 202 | /* no metamethod and (now) there is an entry with given key */ | 215 | /* no metamethod and (now) there is an entry with given key */ |
| 203 | setobj2t(L, cast(TValue *, oldval), val); /* set its new value */ | 216 | setobj2t(L, cast(TValue *, slot), val); /* set its new value */ |
| 204 | invalidateTMcache(h); | 217 | invalidateTMcache(h); |
| 205 | luaC_barrierback(L, h, val); | 218 | luaC_barrierback(L, h, val); |
| 206 | return; | 219 | return; |
| @@ -217,7 +230,7 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, | |||
| 217 | return; | 230 | return; |
| 218 | } | 231 | } |
| 219 | t = tm; /* else repeat assignment over 'tm' */ | 232 | t = tm; /* else repeat assignment over 'tm' */ |
| 220 | if (luaV_fastset(L, t, key, oldval, luaH_get, val)) | 233 | if (luaV_fastset(L, t, key, slot, luaH_get, val)) |
| 221 | return; /* done */ | 234 | return; /* done */ |
| 222 | /* else loop */ | 235 | /* else loop */ |
| 223 | } | 236 | } |
| @@ -748,9 +761,9 @@ void luaV_finishOp (lua_State *L) { | |||
| 748 | ** copy of 'luaV_gettable', but protecting the call to potential | 761 | ** copy of 'luaV_gettable', but protecting the call to potential |
| 749 | ** metamethod (which can reallocate the stack) | 762 | ** metamethod (which can reallocate the stack) |
| 750 | */ | 763 | */ |
| 751 | #define gettableProtected(L,t,k,v) { const TValue *aux; \ | 764 | #define gettableProtected(L,t,k,v) { const TValue *slot; \ |
| 752 | if (luaV_fastget(L,t,k,aux,luaH_get)) { setobj2s(L, v, aux); } \ | 765 | if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \ |
| 753 | else Protect(luaV_finishget(L,t,k,v,aux)); } | 766 | else Protect(luaV_finishget(L,t,k,v,slot)); } |
| 754 | 767 | ||
| 755 | 768 | ||
| 756 | /* same for 'luaV_settable' */ | 769 | /* same for 'luaV_settable' */ |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lvm.h,v 2.38 2015/08/03 20:40:26 roberto Exp roberto $ | 2 | ** $Id: lvm.h,v 2.39 2015/09/09 13:44:07 roberto Exp roberto $ |
| 3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -49,25 +49,24 @@ | |||
| 49 | 49 | ||
| 50 | 50 | ||
| 51 | /* | 51 | /* |
| 52 | ** fast track for 'gettable': 1 means 'aux' points to resulted value; | 52 | ** fast track for 'gettable': if 't' is a table and 't[k]' is not nil, |
| 53 | ** 0 means 'aux' is metamethod (if 't' is a table) or NULL. 'f' is | 53 | ** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise, |
| 54 | ** the raw get function to use. | 54 | ** return 0 (meaning it will have to check metamethod) with 'slot' |
| 55 | ** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise). | ||
| 56 | ** 'f' is the raw get function to use. | ||
| 55 | */ | 57 | */ |
| 56 | #define luaV_fastget(L,t,k,aux,f) \ | 58 | #define luaV_fastget(L,t,k,slot,f) \ |
| 57 | (!ttistable(t) \ | 59 | (!ttistable(t) \ |
| 58 | ? (aux = NULL, 0) /* not a table; 'aux' is NULL and result is 0 */ \ | 60 | ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ |
| 59 | : (aux = f(hvalue(t), k), /* else, do raw access */ \ | 61 | : (slot = f(hvalue(t), k), /* else, do raw access */ \ |
| 60 | !ttisnil(aux) ? 1 /* result not nil? 'aux' has it */ \ | 62 | !ttisnil(slot))) /* result not nil? */ |
| 61 | : (aux = fasttm(L, hvalue(t)->metatable, TM_INDEX), /* get metamethod */\ | ||
| 62 | aux != NULL ? 0 /* has metamethod? must call it */ \ | ||
| 63 | : (aux = luaO_nilobject, 1)))) /* else, final result is nil */ | ||
| 64 | 63 | ||
| 65 | /* | 64 | /* |
| 66 | ** standard implementation for 'gettable' | 65 | ** standard implementation for 'gettable' |
| 67 | */ | 66 | */ |
| 68 | #define luaV_gettable(L,t,k,v) { const TValue *aux; \ | 67 | #define luaV_gettable(L,t,k,v) { const TValue *slot; \ |
| 69 | if (luaV_fastget(L,t,k,aux,luaH_get)) { setobj2s(L, v, aux); } \ | 68 | if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \ |
| 70 | else luaV_finishget(L,t,k,v,aux); } | 69 | else luaV_finishget(L,t,k,v,slot); } |
| 71 | 70 | ||
| 72 | 71 | ||
| 73 | /* | 72 | /* |
| @@ -100,9 +99,9 @@ LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r); | |||
| 100 | LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n); | 99 | LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n); |
| 101 | LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode); | 100 | LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode); |
| 102 | LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, | 101 | LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, |
| 103 | StkId val, const TValue *tm); | 102 | StkId val, const TValue *slot); |
| 104 | LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, | 103 | LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, |
| 105 | StkId val, const TValue *oldval); | 104 | StkId val, const TValue *slot); |
| 106 | LUAI_FUNC void luaV_finishOp (lua_State *L); | 105 | LUAI_FUNC void luaV_finishOp (lua_State *L); |
| 107 | LUAI_FUNC void luaV_execute (lua_State *L); | 106 | LUAI_FUNC void luaV_execute (lua_State *L); |
| 108 | LUAI_FUNC void luaV_concat (lua_State *L, int total); | 107 | LUAI_FUNC void luaV_concat (lua_State *L, int total); |
