summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2017-05-11 15:57:46 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2017-05-11 15:57:46 -0300
commit7647d5d13d016f114dac4be0b9da62d502eab400 (patch)
tree7240a95fd732596e658648f6052b29e551a01265
parent7184f6343a0074d02f6f0e35654cfa55427710d3 (diff)
downloadlua-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.c41
-rw-r--r--lvm.c87
-rw-r--r--lvm.h47
3 files changed, 81 insertions, 94 deletions
diff --git a/lapi.c b/lapi.c
index 2be52631..facf9541 100644
--- a/lapi.c
+++ b/lapi.c
@@ -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
611LUA_API int lua_gettable (lua_State *L, int idx) { 611LUA_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
765LUA_API void lua_settable (lua_State *L, int idx) { 772LUA_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
diff --git a/lvm.c b/lvm.c
index 27d467f3..9a60bb5b 100644
--- a/lvm.c
+++ b/lvm.c
@@ -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*/
202void luaV_finishset (lua_State *L, const TValue *t, TValue *key, 202void 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
823void luaV_execute (lua_State *L) { 796void 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) */
diff --git a/lvm.h b/lvm.h
index ca75a338..17be5842 100644
--- a/lvm.h
+++ b/lvm.h
@@ -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