aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2023-05-15 17:56:25 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2023-05-15 17:56:25 -0300
commit351ccd733298e08c41937c1baf22a68e62bfeca9 (patch)
treebe290db6b41e949c74d6699c7a01963c7cec9b21
parent6443185167c77adcc8552a3fee7edab7895db1a9 (diff)
downloadlua-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.c32
-rw-r--r--ltable.c30
-rw-r--r--ltable.h21
-rw-r--r--lvm.c67
-rw-r--r--lvm.h17
5 files changed, 108 insertions, 59 deletions
diff --git a/lapi.c b/lapi.c
index 34e64af1..2e27bc92 100644
--- a/lapi.c
+++ b/lapi.c
@@ -637,16 +637,16 @@ LUA_API int lua_pushthread (lua_State *L) {
637 637
638 638
639l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) { 639l_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
674LUA_API int lua_gettable (lua_State *L, int idx) { 674LUA_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
695LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { 693LUA_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);
diff --git a/ltable.c b/ltable.c
index 3c690c5f..8fd83fda 100644
--- a/ltable.c
+++ b/ltable.c
@@ -752,6 +752,21 @@ const TValue *luaH_getint (Table *t, lua_Integer key) {
752} 752}
753 753
754 754
755static 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
765int 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
789int luaH_getshortstr1 (Table *t, TString *key, TValue *res) {
790 return finishnodeget(luaH_getshortstr(t, key), res);
791}
792
793
774const TValue *luaH_getstr (Table *t, TString *key) { 794const 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
805int 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
830int 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").
diff --git a/ltable.h b/ltable.h
index 75dd9e26..c8a8c5e7 100644
--- a/ltable.h
+++ b/ltable.h
@@ -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
54LUAI_FUNC int luaH_getshortstr1 (Table *t, TString *key, TValue *res);
55LUAI_FUNC int luaH_getstr1 (Table *t, TString *key, TValue *res);
56LUAI_FUNC int luaH_get1 (Table *t, const TValue *key, TValue *res);
57LUAI_FUNC int luaH_getint1 (Table *t, lua_Integer key, TValue *res);
58
38LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); 59LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
39LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, 60LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
40 TValue *value); 61 TValue *value);
diff --git a/lvm.c b/lvm.c
index 8493a770..ee386847 100644
--- a/lvm.c
+++ b/lvm.c
@@ -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*/
287void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, 287void 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) {
diff --git a/lvm.h b/lvm.h
index dba1ad27..704446c2 100644
--- a/lvm.h
+++ b/lvm.h
@@ -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);
125LUAI_FUNC int luaV_tointegerns (const TValue *obj, lua_Integer *p, 138LUAI_FUNC int luaV_tointegerns (const TValue *obj, lua_Integer *p,
126 F2Imod mode); 139 F2Imod mode);
127LUAI_FUNC int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode); 140LUAI_FUNC int luaV_flttointeger (lua_Number n, lua_Integer *p, F2Imod mode);
128LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, 141LUAI_FUNC void luaV_finishget1 (lua_State *L, const TValue *t, TValue *key,
129 StkId val, const TValue *slot); 142 StkId val, int aux);
130LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, 143LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
131 TValue *val, const TValue *slot); 144 TValue *val, const TValue *slot);
132LUAI_FUNC void luaV_finishOp (lua_State *L); 145LUAI_FUNC void luaV_finishOp (lua_State *L);