diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-05-15 17:56:25 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-05-15 17:56:25 -0300 |
commit | 351ccd733298e08c41937c1baf22a68e62bfeca9 (patch) | |
tree | be290db6b41e949c74d6699c7a01963c7cec9b21 | |
parent | 6443185167c77adcc8552a3fee7edab7895db1a9 (diff) | |
download | lua-351ccd733298e08c41937c1baf22a68e62bfeca9.tar.gz lua-351ccd733298e08c41937c1baf22a68e62bfeca9.tar.bz2 lua-351ccd733298e08c41937c1baf22a68e62bfeca9.zip |
Towards a new implementation of arrays
The array part of a table wastes too much space, due to padding.
To avoid that, we need to store values in the array as something
different from a TValue. Therefore, the API for table access
should not assume that any value in a table lives in a *TValue.
This commit is the first step to remove that assumption: functions
luaH_get*, instead of returning a *TValue where the value lives,
receive a *TValue where to put the value being accessed.
(We still have to change the luaH_set* functions.)
Diffstat (limited to '')
-rw-r--r-- | lapi.c | 32 | ||||
-rw-r--r-- | ltable.c | 30 | ||||
-rw-r--r-- | ltable.h | 21 | ||||
-rw-r--r-- | lvm.c | 67 | ||||
-rw-r--r-- | lvm.h | 17 |
5 files changed, 108 insertions, 59 deletions
@@ -637,16 +637,16 @@ LUA_API int lua_pushthread (lua_State *L) { | |||
637 | 637 | ||
638 | 638 | ||
639 | l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) { | 639 | l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) { |
640 | const TValue *slot; | 640 | int aux; |
641 | TString *str = luaS_new(L, k); | 641 | TString *str = luaS_new(L, k); |
642 | if (luaV_fastget(L, t, str, slot, luaH_getstr)) { | 642 | luaV_fastget1(t, str, s2v(L->top.p), luaH_getstr1, aux); |
643 | setobj2s(L, L->top.p, slot); | 643 | if (aux == HOK) { |
644 | api_incr_top(L); | 644 | api_incr_top(L); |
645 | } | 645 | } |
646 | else { | 646 | else { |
647 | setsvalue2s(L, L->top.p, str); | 647 | setsvalue2s(L, L->top.p, str); |
648 | api_incr_top(L); | 648 | api_incr_top(L); |
649 | luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot); | 649 | luaV_finishget1(L, t, s2v(L->top.p - 1), L->top.p - 1, aux); |
650 | } | 650 | } |
651 | lua_unlock(L); | 651 | lua_unlock(L); |
652 | return ttype(s2v(L->top.p - 1)); | 652 | return ttype(s2v(L->top.p - 1)); |
@@ -672,15 +672,13 @@ LUA_API int lua_getglobal (lua_State *L, const char *name) { | |||
672 | 672 | ||
673 | 673 | ||
674 | LUA_API int lua_gettable (lua_State *L, int idx) { | 674 | LUA_API int lua_gettable (lua_State *L, int idx) { |
675 | const TValue *slot; | 675 | int aux; |
676 | TValue *t; | 676 | TValue *t; |
677 | lua_lock(L); | 677 | lua_lock(L); |
678 | t = index2value(L, idx); | 678 | t = index2value(L, idx); |
679 | if (luaV_fastget(L, t, s2v(L->top.p - 1), slot, luaH_get)) { | 679 | luaV_fastget1(t, s2v(L->top.p - 1), s2v(L->top.p - 1), luaH_get1, aux); |
680 | setobj2s(L, L->top.p - 1, slot); | 680 | if (aux != HOK) |
681 | } | 681 | luaV_finishget1(L, t, s2v(L->top.p - 1), L->top.p - 1, aux); |
682 | else | ||
683 | luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot); | ||
684 | lua_unlock(L); | 682 | lua_unlock(L); |
685 | return ttype(s2v(L->top.p - 1)); | 683 | return ttype(s2v(L->top.p - 1)); |
686 | } | 684 | } |
@@ -694,16 +692,14 @@ LUA_API int lua_getfield (lua_State *L, int idx, const char *k) { | |||
694 | 692 | ||
695 | LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { | 693 | LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { |
696 | TValue *t; | 694 | TValue *t; |
697 | const TValue *slot; | 695 | int aux; |
698 | lua_lock(L); | 696 | lua_lock(L); |
699 | t = index2value(L, idx); | 697 | t = index2value(L, idx); |
700 | if (luaV_fastgeti(L, t, n, slot)) { | 698 | luaV_fastgeti1(t, n, s2v(L->top.p), aux); |
701 | setobj2s(L, L->top.p, slot); | 699 | if (aux != HOK) { |
702 | } | 700 | TValue key; |
703 | else { | 701 | setivalue(&key, n); |
704 | TValue aux; | 702 | luaV_finishget1(L, t, &key, L->top.p, aux); |
705 | setivalue(&aux, n); | ||
706 | luaV_finishget(L, t, &aux, L->top.p, slot); | ||
707 | } | 703 | } |
708 | api_incr_top(L); | 704 | api_incr_top(L); |
709 | lua_unlock(L); | 705 | lua_unlock(L); |
@@ -752,6 +752,21 @@ const TValue *luaH_getint (Table *t, lua_Integer key) { | |||
752 | } | 752 | } |
753 | 753 | ||
754 | 754 | ||
755 | static int finishnodeget (const TValue *val, TValue *res) { | ||
756 | if (!ttisnil(val)) { | ||
757 | setobj(((lua_State*)NULL), res, val); | ||
758 | return HOK; /* success */ | ||
759 | } | ||
760 | else | ||
761 | return HNOTFOUND; /* could not get value */ | ||
762 | } | ||
763 | |||
764 | |||
765 | int luaH_getint1 (Table *t, lua_Integer key, TValue *res) { | ||
766 | return finishnodeget(luaH_getint(t, key), res); | ||
767 | } | ||
768 | |||
769 | |||
755 | /* | 770 | /* |
756 | ** search function for short strings | 771 | ** search function for short strings |
757 | */ | 772 | */ |
@@ -771,6 +786,11 @@ const TValue *luaH_getshortstr (Table *t, TString *key) { | |||
771 | } | 786 | } |
772 | 787 | ||
773 | 788 | ||
789 | int luaH_getshortstr1 (Table *t, TString *key, TValue *res) { | ||
790 | return finishnodeget(luaH_getshortstr(t, key), res); | ||
791 | } | ||
792 | |||
793 | |||
774 | const TValue *luaH_getstr (Table *t, TString *key) { | 794 | const TValue *luaH_getstr (Table *t, TString *key) { |
775 | if (key->tt == LUA_VSHRSTR) | 795 | if (key->tt == LUA_VSHRSTR) |
776 | return luaH_getshortstr(t, key); | 796 | return luaH_getshortstr(t, key); |
@@ -782,6 +802,11 @@ const TValue *luaH_getstr (Table *t, TString *key) { | |||
782 | } | 802 | } |
783 | 803 | ||
784 | 804 | ||
805 | int luaH_getstr1 (Table *t, TString *key, TValue *res) { | ||
806 | return finishnodeget(luaH_getstr(t, key), res); | ||
807 | } | ||
808 | |||
809 | |||
785 | /* | 810 | /* |
786 | ** main search function | 811 | ** main search function |
787 | */ | 812 | */ |
@@ -802,6 +827,11 @@ const TValue *luaH_get (Table *t, const TValue *key) { | |||
802 | } | 827 | } |
803 | 828 | ||
804 | 829 | ||
830 | int luaH_get1 (Table *t, const TValue *key, TValue *res) { | ||
831 | return finishnodeget(luaH_get(t, key), res); | ||
832 | } | ||
833 | |||
834 | |||
805 | /* | 835 | /* |
806 | ** Finish a raw "set table" operation, where 'slot' is where the value | 836 | ** Finish a raw "set table" operation, where 'slot' is where the value |
807 | ** should have been (the result of a previous "get table"). | 837 | ** should have been (the result of a previous "get table"). |
@@ -35,6 +35,27 @@ | |||
35 | #define nodefromval(v) cast(Node *, (v)) | 35 | #define nodefromval(v) cast(Node *, (v)) |
36 | 36 | ||
37 | 37 | ||
38 | /* results from get/set */ | ||
39 | #define HOK 0 | ||
40 | #define HNOTFOUND 1 | ||
41 | #define HNOTATABLE 2 | ||
42 | |||
43 | |||
44 | /* fast access to components of array values */ | ||
45 | #define getArrTag(t,k) (&(t)->array[k - 1].tt_) | ||
46 | #define getArrVal(t,k) (&(t)->array[k - 1].value_) | ||
47 | |||
48 | #define tagisempty(tag) (novariant(tag) == LUA_TNIL) | ||
49 | |||
50 | #define arr2val(h,k,tag,res) \ | ||
51 | ((res)->tt_ = tag, (res)->value_ = *getArrVal(h,k)) | ||
52 | |||
53 | |||
54 | LUAI_FUNC int luaH_getshortstr1 (Table *t, TString *key, TValue *res); | ||
55 | LUAI_FUNC int luaH_getstr1 (Table *t, TString *key, TValue *res); | ||
56 | LUAI_FUNC int luaH_get1 (Table *t, const TValue *key, TValue *res); | ||
57 | LUAI_FUNC int luaH_getint1 (Table *t, lua_Integer key, TValue *res); | ||
58 | |||
38 | LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); | 59 | LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); |
39 | LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, | 60 | LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, |
40 | TValue *value); | 61 | TValue *value); |
@@ -284,12 +284,12 @@ static int floatforloop (StkId ra) { | |||
284 | ** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to | 284 | ** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to |
285 | ** t[k] entry (which must be empty). | 285 | ** t[k] entry (which must be empty). |
286 | */ | 286 | */ |
287 | void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, | 287 | void luaV_finishget1 (lua_State *L, const TValue *t, TValue *key, StkId val, |
288 | const TValue *slot) { | 288 | int aux) { |
289 | int loop; /* counter to avoid infinite loops */ | 289 | int loop; /* counter to avoid infinite loops */ |
290 | const TValue *tm; /* metamethod */ | 290 | const TValue *tm; /* metamethod */ |
291 | for (loop = 0; loop < MAXTAGLOOP; loop++) { | 291 | for (loop = 0; loop < MAXTAGLOOP; loop++) { |
292 | if (slot == NULL) { /* 't' is not a table? */ | 292 | if (aux == HNOTATABLE) { /* 't' is not a table? */ |
293 | lua_assert(!ttistable(t)); | 293 | lua_assert(!ttistable(t)); |
294 | tm = luaT_gettmbyobj(L, t, TM_INDEX); | 294 | tm = luaT_gettmbyobj(L, t, TM_INDEX); |
295 | if (l_unlikely(notm(tm))) | 295 | if (l_unlikely(notm(tm))) |
@@ -297,7 +297,6 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, | |||
297 | /* else will try the metamethod */ | 297 | /* else will try the metamethod */ |
298 | } | 298 | } |
299 | else { /* 't' is a table */ | 299 | else { /* 't' is a table */ |
300 | lua_assert(isempty(slot)); | ||
301 | tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */ | 300 | tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */ |
302 | if (tm == NULL) { /* no metamethod? */ | 301 | if (tm == NULL) { /* no metamethod? */ |
303 | setnilvalue(s2v(val)); /* result is nil */ | 302 | setnilvalue(s2v(val)); /* result is nil */ |
@@ -310,10 +309,9 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, | |||
310 | return; | 309 | return; |
311 | } | 310 | } |
312 | t = tm; /* else try to access 'tm[key]' */ | 311 | t = tm; /* else try to access 'tm[key]' */ |
313 | if (luaV_fastget(L, t, key, slot, luaH_get)) { /* fast track? */ | 312 | luaV_fastget1(t, key, s2v(val), luaH_get1, aux); |
314 | setobj2s(L, val, slot); /* done */ | 313 | if (aux == HOK) |
315 | return; | 314 | return; /* done */ |
316 | } | ||
317 | /* else repeat (tail call 'luaV_finishget') */ | 315 | /* else repeat (tail call 'luaV_finishget') */ |
318 | } | 316 | } |
319 | luaG_runerror(L, "'__index' chain too long; possible loop"); | 317 | luaG_runerror(L, "'__index' chain too long; possible loop"); |
@@ -1250,58 +1248,51 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1250 | } | 1248 | } |
1251 | vmcase(OP_GETTABUP) { | 1249 | vmcase(OP_GETTABUP) { |
1252 | StkId ra = RA(i); | 1250 | StkId ra = RA(i); |
1253 | const TValue *slot; | ||
1254 | TValue *upval = cl->upvals[GETARG_B(i)]->v.p; | 1251 | TValue *upval = cl->upvals[GETARG_B(i)]->v.p; |
1255 | TValue *rc = KC(i); | 1252 | TValue *rc = KC(i); |
1256 | TString *key = tsvalue(rc); /* key must be a string */ | 1253 | TString *key = tsvalue(rc); /* key must be a string */ |
1257 | if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) { | 1254 | int aux; |
1258 | setobj2s(L, ra, slot); | 1255 | luaV_fastget1(upval, key, s2v(ra), luaH_getshortstr1, aux); |
1259 | } | 1256 | if (aux != HOK) |
1260 | else | 1257 | Protect(luaV_finishget1(L, upval, rc, ra, aux)); |
1261 | Protect(luaV_finishget(L, upval, rc, ra, slot)); | ||
1262 | vmbreak; | 1258 | vmbreak; |
1263 | } | 1259 | } |
1264 | vmcase(OP_GETTABLE) { | 1260 | vmcase(OP_GETTABLE) { |
1265 | StkId ra = RA(i); | 1261 | StkId ra = RA(i); |
1266 | const TValue *slot; | ||
1267 | TValue *rb = vRB(i); | 1262 | TValue *rb = vRB(i); |
1268 | TValue *rc = vRC(i); | 1263 | TValue *rc = vRC(i); |
1269 | lua_Unsigned n; | 1264 | int aux; |
1270 | if (ttisinteger(rc) /* fast track for integers? */ | 1265 | if (ttisinteger(rc)) { /* fast track for integers? */ |
1271 | ? (cast_void(n = ivalue(rc)), luaV_fastgeti(L, rb, n, slot)) | 1266 | luaV_fastgeti1(rb, ivalue(rc), s2v(ra), aux); |
1272 | : luaV_fastget(L, rb, rc, slot, luaH_get)) { | ||
1273 | setobj2s(L, ra, slot); | ||
1274 | } | 1267 | } |
1275 | else | 1268 | else |
1276 | Protect(luaV_finishget(L, rb, rc, ra, slot)); | 1269 | luaV_fastget1(rb, rc, s2v(ra), luaH_get1, aux); |
1270 | if (aux != HOK) /* fast track for integers? */ | ||
1271 | Protect(luaV_finishget1(L, rb, rc, ra, aux)); | ||
1277 | vmbreak; | 1272 | vmbreak; |
1278 | } | 1273 | } |
1279 | vmcase(OP_GETI) { | 1274 | vmcase(OP_GETI) { |
1280 | StkId ra = RA(i); | 1275 | StkId ra = RA(i); |
1281 | const TValue *slot; | ||
1282 | TValue *rb = vRB(i); | 1276 | TValue *rb = vRB(i); |
1283 | int c = GETARG_C(i); | 1277 | int c = GETARG_C(i); |
1284 | if (luaV_fastgeti(L, rb, c, slot)) { | 1278 | int aux; |
1285 | setobj2s(L, ra, slot); | 1279 | luaV_fastgeti1(rb, c, s2v(ra), aux); |
1286 | } | 1280 | if (aux != HOK) { |
1287 | else { | ||
1288 | TValue key; | 1281 | TValue key; |
1289 | setivalue(&key, c); | 1282 | setivalue(&key, c); |
1290 | Protect(luaV_finishget(L, rb, &key, ra, slot)); | 1283 | Protect(luaV_finishget1(L, rb, &key, ra, aux)); |
1291 | } | 1284 | } |
1292 | vmbreak; | 1285 | vmbreak; |
1293 | } | 1286 | } |
1294 | vmcase(OP_GETFIELD) { | 1287 | vmcase(OP_GETFIELD) { |
1295 | StkId ra = RA(i); | 1288 | StkId ra = RA(i); |
1296 | const TValue *slot; | ||
1297 | TValue *rb = vRB(i); | 1289 | TValue *rb = vRB(i); |
1298 | TValue *rc = KC(i); | 1290 | TValue *rc = KC(i); |
1299 | TString *key = tsvalue(rc); /* key must be a string */ | 1291 | TString *key = tsvalue(rc); /* key must be a string */ |
1300 | if (luaV_fastget(L, rb, key, slot, luaH_getshortstr)) { | 1292 | int aux; |
1301 | setobj2s(L, ra, slot); | 1293 | luaV_fastget1(rb, key, s2v(ra), luaH_getshortstr1, aux); |
1302 | } | 1294 | if (aux != HOK) |
1303 | else | 1295 | Protect(luaV_finishget1(L, rb, rc, ra, aux)); |
1304 | Protect(luaV_finishget(L, rb, rc, ra, slot)); | ||
1305 | vmbreak; | 1296 | vmbreak; |
1306 | } | 1297 | } |
1307 | vmcase(OP_SETTABUP) { | 1298 | vmcase(OP_SETTABUP) { |
@@ -1381,16 +1372,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1381 | } | 1372 | } |
1382 | vmcase(OP_SELF) { | 1373 | vmcase(OP_SELF) { |
1383 | StkId ra = RA(i); | 1374 | StkId ra = RA(i); |
1384 | const TValue *slot; | 1375 | int aux; |
1385 | TValue *rb = vRB(i); | 1376 | TValue *rb = vRB(i); |
1386 | TValue *rc = RKC(i); | 1377 | TValue *rc = RKC(i); |
1387 | TString *key = tsvalue(rc); /* key must be a string */ | 1378 | TString *key = tsvalue(rc); /* key must be a string */ |
1388 | setobj2s(L, ra + 1, rb); | 1379 | setobj2s(L, ra + 1, rb); |
1389 | if (luaV_fastget(L, rb, key, slot, luaH_getstr)) { | 1380 | luaV_fastget1(rb, key, s2v(ra), luaH_getstr1, aux); |
1390 | setobj2s(L, ra, slot); | 1381 | if (aux != HOK) |
1391 | } | 1382 | Protect(luaV_finishget1(L, rb, rc, ra, aux)); |
1392 | else | ||
1393 | Protect(luaV_finishget(L, rb, rc, ra, slot)); | ||
1394 | vmbreak; | 1383 | vmbreak; |
1395 | } | 1384 | } |
1396 | vmcase(OP_ADDI) { | 1385 | vmcase(OP_ADDI) { |
@@ -89,6 +89,10 @@ typedef enum { | |||
89 | !isempty(slot))) /* result not empty? */ | 89 | !isempty(slot))) /* result not empty? */ |
90 | 90 | ||
91 | 91 | ||
92 | #define luaV_fastget1(t,k,res,f, aux) \ | ||
93 | (aux = (!ttistable(t) ? HNOTATABLE : f(hvalue(t), k, res))) | ||
94 | |||
95 | |||
92 | /* | 96 | /* |
93 | ** Special case of 'luaV_fastget' for integers, inlining the fast case | 97 | ** Special case of 'luaV_fastget' for integers, inlining the fast case |
94 | ** of 'luaH_getint'. | 98 | ** of 'luaH_getint'. |
@@ -100,6 +104,15 @@ typedef enum { | |||
100 | ? &hvalue(t)->array[k - 1] : luaH_getint(hvalue(t), k), \ | 104 | ? &hvalue(t)->array[k - 1] : luaH_getint(hvalue(t), k), \ |
101 | !isempty(slot))) /* result not empty? */ | 105 | !isempty(slot))) /* result not empty? */ |
102 | 106 | ||
107 | #define luaV_fastgeti1(t,k,val,aux) \ | ||
108 | if (!ttistable(t)) aux = HNOTATABLE; \ | ||
109 | else { Table *h = hvalue(t); lua_Unsigned u = l_castS2U(k); \ | ||
110 | if ((u - 1u < h->alimit)) { \ | ||
111 | int tag = *getArrTag(h,u); \ | ||
112 | if (tagisempty(tag)) aux = HNOTFOUND; \ | ||
113 | else { arr2val(h, u, tag, val); aux = HOK; }} \ | ||
114 | else { aux = luaH_getint1(h, u, val); }} | ||
115 | |||
103 | 116 | ||
104 | /* | 117 | /* |
105 | ** Finish a fast set operation (when fast get succeeds). In that case, | 118 | ** Finish a fast set operation (when fast get succeeds). In that case, |
@@ -125,8 +138,8 @@ LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, F2Imod mode); | |||
125 | LUAI_FUNC int luaV_tointegerns (const TValue *obj, lua_Integer *p, | 138 | LUAI_FUNC int luaV_tointegerns (const TValue *obj, lua_Integer *p, |
126 | F2Imod mode); | 139 | F2Imod mode); |
127 | LUAI_FUNC int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode); | 140 | LUAI_FUNC int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode); |
128 | LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, | 141 | LUAI_FUNC void luaV_finishget1 (lua_State *L, const TValue *t, TValue *key, |
129 | StkId val, const TValue *slot); | 142 | StkId val, int aux); |
130 | LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, | 143 | LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, |
131 | TValue *val, const TValue *slot); | 144 | TValue *val, const TValue *slot); |
132 | LUAI_FUNC void luaV_finishOp (lua_State *L); | 145 | LUAI_FUNC void luaV_finishOp (lua_State *L); |