diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-05-11 15:57:46 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-05-11 15:57:46 -0300 |
commit | 7647d5d13d016f114dac4be0b9da62d502eab400 (patch) | |
tree | 7240a95fd732596e658648f6052b29e551a01265 | |
parent | 7184f6343a0074d02f6f0e35654cfa55427710d3 (diff) | |
download | lua-7647d5d13d016f114dac4be0b9da62d502eab400.tar.gz lua-7647d5d13d016f114dac4be0b9da62d502eab400.tar.bz2 lua-7647d5d13d016f114dac4be0b9da62d502eab400.zip |
revamp of fast track for table access (table set uses the same
macros as table get + new macro for integer keys)
-rw-r--r-- | lapi.c | 41 | ||||
-rw-r--r-- | lvm.c | 87 | ||||
-rw-r--r-- | lvm.h | 47 |
3 files changed, 81 insertions, 94 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lapi.c,v 2.264 2017/04/20 18:22:44 roberto Exp roberto $ | 2 | ** $Id: lapi.c,v 2.265 2017/04/24 16:59:26 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 | */ |
@@ -609,10 +609,15 @@ LUA_API int lua_getglobal (lua_State *L, const char *name) { | |||
609 | 609 | ||
610 | 610 | ||
611 | LUA_API int lua_gettable (lua_State *L, int idx) { | 611 | LUA_API int lua_gettable (lua_State *L, int idx) { |
612 | const TValue *slot; | ||
612 | StkId t; | 613 | StkId t; |
613 | lua_lock(L); | 614 | lua_lock(L); |
614 | t = index2addr(L, idx); | 615 | t = index2addr(L, idx); |
615 | luaV_gettable(L, t, L->top - 1, L->top - 1); | 616 | if (luaV_fastget(L, t, L->top - 1, slot, luaH_get)) { |
617 | setobj2s(L, L->top - 1, slot); | ||
618 | } | ||
619 | else | ||
620 | luaV_finishget(L, t, L->top - 1, L->top - 1, slot); | ||
616 | lua_unlock(L); | 621 | lua_unlock(L); |
617 | return ttnov(L->top - 1); | 622 | return ttnov(L->top - 1); |
618 | } | 623 | } |
@@ -629,15 +634,15 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { | |||
629 | const TValue *slot; | 634 | const TValue *slot; |
630 | lua_lock(L); | 635 | lua_lock(L); |
631 | t = index2addr(L, idx); | 636 | t = index2addr(L, idx); |
632 | if (luaV_fastget(L, t, n, slot, luaH_getint)) { | 637 | if (luaV_fastgeti(L, t, n, slot)) { |
633 | setobj2s(L, L->top, slot); | 638 | setobj2s(L, L->top, slot); |
634 | api_incr_top(L); | ||
635 | } | 639 | } |
636 | else { | 640 | else { |
637 | setivalue(L->top, n); | 641 | TValue aux; |
638 | api_incr_top(L); | 642 | setivalue(&aux, n); |
639 | luaV_finishget(L, t, L->top - 1, L->top - 1, slot); | 643 | luaV_finishget(L, t, &aux, L->top, slot); |
640 | } | 644 | } |
645 | api_incr_top(L); | ||
641 | lua_unlock(L); | 646 | lua_unlock(L); |
642 | return ttnov(L->top - 1); | 647 | return ttnov(L->top - 1); |
643 | } | 648 | } |
@@ -743,8 +748,10 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) { | |||
743 | const TValue *slot; | 748 | const TValue *slot; |
744 | TString *str = luaS_new(L, k); | 749 | TString *str = luaS_new(L, k); |
745 | api_checknelems(L, 1); | 750 | api_checknelems(L, 1); |
746 | if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1)) | 751 | if (luaV_fastget(L, t, str, slot, luaH_getstr)) { |
752 | luaV_finishfastset(L, t, slot, L->top - 1); | ||
747 | L->top--; /* pop value */ | 753 | L->top--; /* pop value */ |
754 | } | ||
748 | else { | 755 | else { |
749 | setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ | 756 | setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ |
750 | api_incr_top(L); | 757 | api_incr_top(L); |
@@ -764,10 +771,14 @@ LUA_API void lua_setglobal (lua_State *L, const char *name) { | |||
764 | 771 | ||
765 | LUA_API void lua_settable (lua_State *L, int idx) { | 772 | LUA_API void lua_settable (lua_State *L, int idx) { |
766 | StkId t; | 773 | StkId t; |
774 | const TValue *slot; | ||
767 | lua_lock(L); | 775 | lua_lock(L); |
768 | api_checknelems(L, 2); | 776 | api_checknelems(L, 2); |
769 | t = index2addr(L, idx); | 777 | t = index2addr(L, idx); |
770 | luaV_settable(L, t, L->top - 2, L->top - 1); | 778 | if (luaV_fastget(L, t, L->top - 2, slot, luaH_get)) |
779 | luaV_finishfastset(L, t, slot, L->top - 1); | ||
780 | else | ||
781 | luaV_finishset(L, t, L->top - 2, L->top - 1, slot); | ||
771 | L->top -= 2; /* pop index and value */ | 782 | L->top -= 2; /* pop index and value */ |
772 | lua_unlock(L); | 783 | lua_unlock(L); |
773 | } | 784 | } |
@@ -785,14 +796,14 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { | |||
785 | lua_lock(L); | 796 | lua_lock(L); |
786 | api_checknelems(L, 1); | 797 | api_checknelems(L, 1); |
787 | t = index2addr(L, idx); | 798 | t = index2addr(L, idx); |
788 | if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1)) | 799 | if (luaV_fastgeti(L, t, n, slot)) |
789 | L->top--; /* pop value */ | 800 | luaV_finishfastset(L, t, slot, L->top - 1); |
790 | else { | 801 | else { |
791 | setivalue(L->top, n); | 802 | TValue aux; |
792 | api_incr_top(L); | 803 | setivalue(&aux, n); |
793 | luaV_finishset(L, t, L->top - 1, L->top - 2, slot); | 804 | luaV_finishset(L, t, &aux, L->top - 1, slot); |
794 | L->top -= 2; /* pop value and key */ | ||
795 | } | 805 | } |
806 | L->top--; /* pop value */ | ||
796 | lua_unlock(L); | 807 | lua_unlock(L); |
797 | } | 808 | } |
798 | 809 | ||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lvm.c,v 2.278 2017/05/08 16:08:01 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 2.279 2017/05/10 17:32:19 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 | */ |
@@ -182,7 +182,7 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, | |||
182 | return; | 182 | return; |
183 | } | 183 | } |
184 | t = tm; /* else try to access 'tm[key]' */ | 184 | t = tm; /* else try to access 'tm[key]' */ |
185 | if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */ | 185 | if (luaV_fastget(L, t, key, slot, luaH_get)) { /* fast track? */ |
186 | setobj2s(L, val, slot); /* done */ | 186 | setobj2s(L, val, slot); /* done */ |
187 | return; | 187 | return; |
188 | } | 188 | } |
@@ -196,7 +196,7 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, | |||
196 | ** Finish a table assignment 't[key] = val'. | 196 | ** Finish a table assignment 't[key] = val'. |
197 | ** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points | 197 | ** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points |
198 | ** to the entry 't[key]', or to 'luaO_nilobject' if there is no such | 198 | ** to the entry 't[key]', or to 'luaO_nilobject' if there is no such |
199 | ** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset' | 199 | ** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastget' |
200 | ** would have done the job.) | 200 | ** would have done the job.) |
201 | */ | 201 | */ |
202 | void luaV_finishset (lua_State *L, const TValue *t, TValue *key, | 202 | 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, | |||
229 | return; | 229 | return; |
230 | } | 230 | } |
231 | t = tm; /* else repeat assignment over 'tm' */ | 231 | t = tm; /* else repeat assignment over 'tm' */ |
232 | if (luaV_fastset(L, t, key, slot, luaH_get, val)) | 232 | if (luaV_fastget(L, t, key, slot, luaH_get)) { |
233 | luaV_finishfastset(L, t, slot, val); | ||
233 | return; /* done */ | 234 | return; /* done */ |
234 | /* else loop */ | 235 | } |
236 | /* else 'return luaV_finishset(L, t, key, val, slot)' (loop) */ | ||
235 | } | 237 | } |
236 | luaG_runerror(L, "'__newindex' chain too long; possible loop"); | 238 | luaG_runerror(L, "'__newindex' chain too long; possible loop"); |
237 | } | 239 | } |
@@ -791,35 +793,6 @@ void luaV_finishOp (lua_State *L) { | |||
791 | #define vmbreak break | 793 | #define vmbreak break |
792 | 794 | ||
793 | 795 | ||
794 | /* | ||
795 | ** copy of 'luaV_gettable', but protecting the call to potential | ||
796 | ** metamethod (which can reallocate the stack) | ||
797 | */ | ||
798 | #define gettableProtected(L,t,k,v) { const TValue *slot; \ | ||
799 | if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \ | ||
800 | else Protect(luaV_finishget(L,t,k,v,slot)); } | ||
801 | |||
802 | |||
803 | /* same for 'luaV_settable' */ | ||
804 | #define settableProtected(L,t,k,v) { const TValue *slot; \ | ||
805 | if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \ | ||
806 | Protect(luaV_finishset(L,t,k,v,slot)); } | ||
807 | |||
808 | |||
809 | /* | ||
810 | ** Predicate for integer fast track in GET/SETTABLE. | ||
811 | ** (Strings are usually constant and therefore coded with | ||
812 | ** GET/SETFIELD). Check that index is an integer, "table" is | ||
813 | ** a table, index is in the array part, and value is not nil | ||
814 | ** (otherwise it will need metamethods). Use 'n' and 't' for | ||
815 | ** for caching the integer and table values. | ||
816 | */ | ||
817 | #define fastintindex(tbl,idx,t,n) \ | ||
818 | (ttisinteger(idx) && ttistable(tbl) && \ | ||
819 | (n = l_castS2U(ivalue(idx)) - 1u, t = hvalue(tbl), \ | ||
820 | n < t->sizearray) && !ttisnil(&t->array[n])) | ||
821 | |||
822 | |||
823 | void luaV_execute (lua_State *L) { | 796 | void luaV_execute (lua_State *L) { |
824 | CallInfo *ci = L->ci; | 797 | CallInfo *ci = L->ci; |
825 | LClosure *cl; | 798 | LClosure *cl; |
@@ -899,21 +872,24 @@ void luaV_execute (lua_State *L) { | |||
899 | vmbreak; | 872 | vmbreak; |
900 | } | 873 | } |
901 | vmcase(OP_GETTABLE) { | 874 | vmcase(OP_GETTABLE) { |
875 | const TValue *slot; | ||
902 | StkId rb = RB(i); | 876 | StkId rb = RB(i); |
903 | TValue *rc = RC(i); | 877 | TValue *rc = RC(i); |
904 | Table *t; lua_Unsigned n; | 878 | lua_Unsigned n; |
905 | if (fastintindex(rb, rc, t, n)) { | 879 | if (ttisinteger(rc) /* fast track for integers? */ |
906 | setobj2s(L, ra, &t->array[n]); | 880 | ? (n = ivalue(rc), luaV_fastgeti(L, rb, n, slot)) |
881 | : luaV_fastget(L, rb, rc, slot, luaH_get)) { | ||
882 | setobj2s(L, ra, slot); | ||
907 | } | 883 | } |
908 | else | 884 | else |
909 | gettableProtected(L, rb, rc, ra); | 885 | Protect(luaV_finishget(L, rb, rc, ra, slot)); |
910 | vmbreak; | 886 | vmbreak; |
911 | } | 887 | } |
912 | vmcase(OP_GETI) { | 888 | vmcase(OP_GETI) { |
913 | const TValue *slot; | 889 | const TValue *slot; |
914 | StkId rb = RB(i); | 890 | StkId rb = RB(i); |
915 | int c = GETARG_C(i); | 891 | int c = GETARG_C(i); |
916 | if (luaV_fastget(L, rb, c, slot, luaH_getint)) { | 892 | if (luaV_fastgeti(L, rb, c, slot)) { |
917 | setobj2s(L, ra, slot); | 893 | setobj2s(L, ra, slot); |
918 | } | 894 | } |
919 | else { | 895 | else { |
@@ -940,26 +916,32 @@ void luaV_execute (lua_State *L) { | |||
940 | TValue *rb = KB(i); | 916 | TValue *rb = KB(i); |
941 | TValue *rc = RKC(i); | 917 | TValue *rc = RKC(i); |
942 | TString *key = tsvalue(rb); /* key must be a string */ | 918 | TString *key = tsvalue(rb); /* key must be a string */ |
943 | if (!luaV_fastset(L, upval, key, slot, luaH_getstr, rc)) | 919 | if (luaV_fastget(L, upval, key, slot, luaH_getstr)) |
920 | luaV_finishfastset(L, upval, slot, rc); | ||
921 | else | ||
944 | Protect(luaV_finishset(L, upval, rb, rc, slot)); | 922 | Protect(luaV_finishset(L, upval, rb, rc, slot)); |
945 | vmbreak; | 923 | vmbreak; |
946 | } | 924 | } |
947 | vmcase(OP_SETTABLE) { | 925 | vmcase(OP_SETTABLE) { |
948 | TValue *rb = RB(i); | 926 | const TValue *slot; |
949 | TValue *rc = RKC(i); | 927 | TValue *rb = RB(i); /* key (table is in 'ra') */ |
950 | Table *t; lua_Unsigned n; | 928 | TValue *rc = RKC(i); /* value */ |
951 | if (fastintindex(ra, rb, t, n)) { | 929 | lua_Unsigned n; |
952 | setobj2t(L, &t->array[n], rc); | 930 | if (ttisinteger(rb) /* fast track for integers? */ |
953 | } | 931 | ? (n = ivalue(rb), luaV_fastgeti(L, ra, n, slot)) |
932 | : luaV_fastget(L, ra, rb, slot, luaH_get)) | ||
933 | luaV_finishfastset(L, ra, slot, rc); | ||
954 | else | 934 | else |
955 | settableProtected(L, ra, rb, rc); | 935 | Protect(luaV_finishset(L, ra, rb, rc, slot)); |
956 | vmbreak; | 936 | vmbreak; |
957 | } | 937 | } |
958 | vmcase(OP_SETI) { | 938 | vmcase(OP_SETI) { |
959 | const TValue *slot; | 939 | const TValue *slot; |
960 | int c = GETARG_B(i); | 940 | int c = GETARG_B(i); |
961 | TValue *rc = RKC(i); | 941 | TValue *rc = RKC(i); |
962 | if (!luaV_fastset(L, ra, c, slot, luaH_getint, rc)) { | 942 | if (luaV_fastgeti(L, ra, c, slot)) |
943 | luaV_finishfastset(L, ra, slot, rc); | ||
944 | else { | ||
963 | TValue key; | 945 | TValue key; |
964 | setivalue(&key, c); | 946 | setivalue(&key, c); |
965 | Protect(luaV_finishset(L, ra, &key, rc, slot)); | 947 | Protect(luaV_finishset(L, ra, &key, rc, slot)); |
@@ -971,7 +953,9 @@ void luaV_execute (lua_State *L) { | |||
971 | TValue *rb = KB(i); | 953 | TValue *rb = KB(i); |
972 | TValue *rc = RKC(i); | 954 | TValue *rc = RKC(i); |
973 | TString *key = tsvalue(rb); /* key must be a string */ | 955 | TString *key = tsvalue(rb); /* key must be a string */ |
974 | if (!luaV_fastset(L, ra, key, slot, luaH_getstr, rc)) | 956 | if (luaV_fastget(L, ra, key, slot, luaH_getstr)) |
957 | luaV_finishfastset(L, ra, slot, rc); | ||
958 | else | ||
975 | Protect(luaV_finishset(L, ra, rb, rc, slot)); | 959 | Protect(luaV_finishset(L, ra, rb, rc, slot)); |
976 | vmbreak; | 960 | vmbreak; |
977 | } | 961 | } |
@@ -1427,8 +1411,9 @@ void luaV_execute (lua_State *L) { | |||
1427 | if (last > h->sizearray) /* needs more space? */ | 1411 | if (last > h->sizearray) /* needs more space? */ |
1428 | luaH_resizearray(L, h, last); /* preallocate it at once */ | 1412 | luaH_resizearray(L, h, last); /* preallocate it at once */ |
1429 | for (; n > 0; n--) { | 1413 | for (; n > 0; n--) { |
1430 | TValue *val = ra+n; | 1414 | TValue *val = ra + n; |
1431 | luaH_setint(L, h, last--, val); | 1415 | setobj2t(L, &h->array[last - 1], val); |
1416 | last--; | ||
1432 | luaC_barrierback(L, h, val); | 1417 | luaC_barrierback(L, h, val); |
1433 | } | 1418 | } |
1434 | L->top = ci->top; /* correct top (in case of previous open call) */ | 1419 | L->top = ci->top; /* correct top (in case of previous open call) */ |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lvm.h,v 2.40 2016/01/05 16:07:21 roberto Exp roberto $ | 2 | ** $Id: lvm.h,v 2.41 2016/12/22 13:08: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 | */ |
@@ -50,10 +50,10 @@ | |||
50 | 50 | ||
51 | /* | 51 | /* |
52 | ** fast track for 'gettable': if 't' is a table and 't[k]' is not nil, | 52 | ** fast track for 'gettable': if 't' is a table and 't[k]' is not nil, |
53 | ** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise, | 53 | ** return 1 with 'slot' pointing to 't[k]' (position of final result). |
54 | ** return 0 (meaning it will have to check metamethod) with 'slot' | 54 | ** Otherwise, return 0 (meaning it will have to check metamethod) |
55 | ** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise). | 55 | ** with 'slot' pointing to a nil 't[k]' (if 't' is a table) or NULL |
56 | ** 'f' is the raw get function to use. | 56 | ** (otherwise). 'f' is the raw get function to use. |
57 | */ | 57 | */ |
58 | #define luaV_fastget(L,t,k,slot,f) \ | 58 | #define luaV_fastget(L,t,k,slot,f) \ |
59 | (!ttistable(t) \ | 59 | (!ttistable(t) \ |
@@ -61,35 +61,26 @@ | |||
61 | : (slot = f(hvalue(t), k), /* else, do raw access */ \ | 61 | : (slot = f(hvalue(t), k), /* else, do raw access */ \ |
62 | !ttisnil(slot))) /* result not nil? */ | 62 | !ttisnil(slot))) /* result not nil? */ |
63 | 63 | ||
64 | |||
64 | /* | 65 | /* |
65 | ** standard implementation for 'gettable' | 66 | ** Special case of 'luaV_fastget' for integers, inlining the fast case |
67 | ** of 'luaH_getint'. | ||
66 | */ | 68 | */ |
67 | #define luaV_gettable(L,t,k,v) { const TValue *slot; \ | 69 | #define luaV_fastgeti(L,t,k,slot) \ |
68 | if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \ | 70 | (!ttistable(t) \ |
69 | else luaV_finishget(L,t,k,v,slot); } | 71 | ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \ |
72 | : (slot = (l_castS2U(k) - 1u < hvalue(t)->sizearray) \ | ||
73 | ? &hvalue(t)->array[k - 1] : luaH_getint(hvalue(t), k), \ | ||
74 | !ttisnil(slot))) /* result not nil? */ | ||
70 | 75 | ||
71 | 76 | ||
72 | /* | 77 | /* |
73 | ** Fast track for set table. If 't' is a table and 't[k]' is not nil, | 78 | ** Finish a fast set operation (when fast get succeeds). In that case, |
74 | ** call GC barrier, do a raw 't[k]=v', and return true; otherwise, | 79 | ** 'slot' points to the place to put the value. |
75 | ** return false with 'slot' equal to NULL (if 't' is not a table) or | ||
76 | ** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro | ||
77 | ** returns true, there is no need to 'invalidateTMcache', because the | ||
78 | ** call is not creating a new entry. | ||
79 | */ | 80 | */ |
80 | #define luaV_fastset(L,t,k,slot,f,v) \ | 81 | #define luaV_finishfastset(L,t,slot,v) \ |
81 | (!ttistable(t) \ | 82 | (setobj2t(L, cast(TValue *,slot), v), luaC_barrierback(L, hvalue(t), v)) |
82 | ? (slot = NULL, 0) \ | 83 | |
83 | : (slot = f(hvalue(t), k), \ | ||
84 | ttisnil(slot) ? 0 \ | ||
85 | : (luaC_barrierback(L, hvalue(t), v), \ | ||
86 | setobj2t(L, cast(TValue *,slot), v), \ | ||
87 | 1))) | ||
88 | |||
89 | |||
90 | #define luaV_settable(L,t,k,v) { const TValue *slot; \ | ||
91 | if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \ | ||
92 | luaV_finishset(L,t,k,v,slot); } | ||
93 | 84 | ||
94 | 85 | ||
95 | 86 | ||