aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2023-11-03 15:26:13 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2023-11-03 15:26:13 -0300
commit08a077d673b25cf1fbfe21794f240f4ff4999667 (patch)
tree77ae945c9a2680af23d5fa11c156482b35c14e04
parent43c8e5bded052801f54a7439d18933b83570eb82 (diff)
downloadlua-08a077d673b25cf1fbfe21794f240f4ff4999667.tar.gz
lua-08a077d673b25cf1fbfe21794f240f4ff4999667.tar.bz2
lua-08a077d673b25cf1fbfe21794f240f4ff4999667.zip
Full implementation of new representation for arrays
Diffstat (limited to '')
-rw-r--r--lgc.c8
-rw-r--r--lobject.h4
-rw-r--r--ltable.c46
-rw-r--r--ltable.h63
-rw-r--r--lvm.h4
5 files changed, 96 insertions, 29 deletions
diff --git a/lgc.c b/lgc.c
index 813b08d5..0f423282 100644
--- a/lgc.c
+++ b/lgc.c
@@ -493,7 +493,7 @@ static int traverseephemeron (global_State *g, Table *h, int inv) {
493 unsigned int nsize = sizenode(h); 493 unsigned int nsize = sizenode(h);
494 /* traverse array part */ 494 /* traverse array part */
495 for (i = 0; i < asize; i++) { 495 for (i = 0; i < asize; i++) {
496 GCObject *o = gcvalarr(h, i + 1); 496 GCObject *o = gcvalarr(h, i);
497 if (o != NULL && iswhite(o)) { 497 if (o != NULL && iswhite(o)) {
498 marked = 1; 498 marked = 1;
499 reallymarkobject(g, o); 499 reallymarkobject(g, o);
@@ -533,7 +533,7 @@ static void traversestrongtable (global_State *g, Table *h) {
533 unsigned int i; 533 unsigned int i;
534 unsigned int asize = luaH_realasize(h); 534 unsigned int asize = luaH_realasize(h);
535 for (i = 0; i < asize; i++) { /* traverse array part */ 535 for (i = 0; i < asize; i++) { /* traverse array part */
536 GCObject *o = gcvalarr(h, i + 1); 536 GCObject *o = gcvalarr(h, i);
537 if (o != NULL && iswhite(o)) 537 if (o != NULL && iswhite(o))
538 reallymarkobject(g, o); 538 reallymarkobject(g, o);
539 } 539 }
@@ -757,9 +757,9 @@ static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) {
757 unsigned int i; 757 unsigned int i;
758 unsigned int asize = luaH_realasize(h); 758 unsigned int asize = luaH_realasize(h);
759 for (i = 0; i < asize; i++) { 759 for (i = 0; i < asize; i++) {
760 GCObject *o = gcvalarr(h, i + 1); 760 GCObject *o = gcvalarr(h, i);
761 if (iscleared(g, o)) /* value was collected? */ 761 if (iscleared(g, o)) /* value was collected? */
762 *getArrTag(h, i + 1) = LUA_VEMPTY; /* remove entry */ 762 *getArrTag(h, i) = LUA_VEMPTY; /* remove entry */
763 } 763 }
764 for (n = gnode(h, 0); n < limit; n++) { 764 for (n = gnode(h, 0); n < limit; n++) {
765 if (iscleared(g, gcvalueN(gval(n)))) /* unmarked value? */ 765 if (iscleared(g, gcvalueN(gval(n)))) /* unmarked value? */
diff --git a/lobject.h b/lobject.h
index e91bb0f8..25e268be 100644
--- a/lobject.h
+++ b/lobject.h
@@ -192,6 +192,8 @@ typedef union {
192/* macro to test for (any kind of) nil */ 192/* macro to test for (any kind of) nil */
193#define ttisnil(v) checktype((v), LUA_TNIL) 193#define ttisnil(v) checktype((v), LUA_TNIL)
194 194
195#define tagisempty(tag) (novariant(tag) == LUA_TNIL)
196
195 197
196/* macro to test for a standard nil */ 198/* macro to test for a standard nil */
197#define ttisstrictnil(o) checktag((o), LUA_VNIL) 199#define ttisstrictnil(o) checktag((o), LUA_VNIL)
@@ -736,7 +738,7 @@ typedef union Node {
736#define setnorealasize(t) ((t)->flags |= BITRAS) 738#define setnorealasize(t) ((t)->flags |= BITRAS)
737 739
738 740
739typedef struct ArrayCell ArrayCell; 741typedef union ArrayCell ArrayCell;
740 742
741 743
742typedef struct Table { 744typedef struct Table {
diff --git a/ltable.c b/ltable.c
index ddda9a44..b7362a36 100644
--- a/ltable.c
+++ b/ltable.c
@@ -350,7 +350,7 @@ int luaH_next (lua_State *L, Table *t, StkId key) {
350 unsigned int asize = luaH_realasize(t); 350 unsigned int asize = luaH_realasize(t);
351 unsigned int i = findindex(L, t, s2v(key), asize); /* find original key */ 351 unsigned int i = findindex(L, t, s2v(key), asize); /* find original key */
352 for (; i < asize; i++) { /* try first array part */ 352 for (; i < asize; i++) { /* try first array part */
353 int tag = *getArrTag(t, i + 1); 353 int tag = *getArrTag(t, i);
354 if (!tagisempty(tag)) { /* a non-empty entry? */ 354 if (!tagisempty(tag)) { /* a non-empty entry? */
355 setivalue(s2v(key), i + 1); 355 setivalue(s2v(key), i + 1);
356 farr2val(t, i + 1, tag, s2v(key + 1)); 356 farr2val(t, i + 1, tag, s2v(key + 1));
@@ -458,7 +458,7 @@ static int countint (lua_Integer key, unsigned int *nums) {
458 458
459 459
460l_sinline int arraykeyisempty (const Table *t, lua_Integer key) { 460l_sinline int arraykeyisempty (const Table *t, lua_Integer key) {
461 int tag = *getArrTag(t, key); 461 int tag = *getArrTag(t, key - 1);
462 return tagisempty(tag); 462 return tagisempty(tag);
463} 463}
464 464
@@ -513,6 +513,33 @@ static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) {
513 513
514 514
515/* 515/*
516** Convert an "abstract size" (number of values in an array) to
517** "concrete size" (number of cell elements in the array). Cells
518** do not need to be full; we only must make sure it has the values
519** needed and its 'tag' element. So, we compute the concrete tag index
520** and the concrete value index of the last element, get their maximum
521** and adds 1.
522*/
523static unsigned int concretesize (unsigned int size) {
524 if (size == 0) return 0;
525 else {
526 unsigned int ts = TagIndex(size - 1);
527 unsigned int vs = ValueIndex(size - 1);
528 return ((ts >= vs) ? ts : vs) + 1;
529 }
530}
531
532
533static ArrayCell *resizearray (lua_State *L , Table *t,
534 unsigned int oldasize,
535 unsigned int newasize) {
536 oldasize = concretesize(oldasize);
537 newasize = concretesize(newasize);
538 return luaM_reallocvector(L, t->array, oldasize, newasize, ArrayCell);
539}
540
541
542/*
516** Creates an array for the hash part of a table with the given 543** Creates an array for the hash part of a table with the given
517** size, or reuses the dummy node if size is zero. 544** size, or reuses the dummy node if size is zero.
518** The computation for size overflow is in two steps: the first 545** The computation for size overflow is in two steps: the first
@@ -605,7 +632,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize,
605 exchangehashpart(t, &newt); /* and new hash */ 632 exchangehashpart(t, &newt); /* and new hash */
606 /* re-insert into the new hash the elements from vanishing slice */ 633 /* re-insert into the new hash the elements from vanishing slice */
607 for (i = newasize; i < oldasize; i++) { 634 for (i = newasize; i < oldasize; i++) {
608 int tag = *getArrTag(t, i + 1); 635 int tag = *getArrTag(t, i);
609 if (!tagisempty(tag)) { /* a non-empty entry? */ 636 if (!tagisempty(tag)) { /* a non-empty entry? */
610 TValue aux; 637 TValue aux;
611 farr2val(t, i + 1, tag, &aux); 638 farr2val(t, i + 1, tag, &aux);
@@ -616,7 +643,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize,
616 exchangehashpart(t, &newt); /* and hash (in case of errors) */ 643 exchangehashpart(t, &newt); /* and hash (in case of errors) */
617 } 644 }
618 /* allocate new array */ 645 /* allocate new array */
619 newarray = luaM_reallocvector(L, t->array, oldasize, newasize, ArrayCell); 646 newarray = resizearray(L, t, oldasize, newasize);
620 if (l_unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */ 647 if (l_unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */
621 freehash(L, &newt); /* release new hash part */ 648 freehash(L, &newt); /* release new hash part */
622 luaM_error(L); /* raise error (with array unchanged) */ 649 luaM_error(L); /* raise error (with array unchanged) */
@@ -626,7 +653,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize,
626 t->array = newarray; /* set new array part */ 653 t->array = newarray; /* set new array part */
627 t->alimit = newasize; 654 t->alimit = newasize;
628 for (i = oldasize; i < newasize; i++) /* clear new slice of the array */ 655 for (i = oldasize; i < newasize; i++) /* clear new slice of the array */
629 *getArrTag(t, i + 1) = LUA_VEMPTY; 656 *getArrTag(t, i) = LUA_VEMPTY;
630 /* re-insert elements from old hash part into new parts */ 657 /* re-insert elements from old hash part into new parts */
631 reinsert(L, &newt, t); /* 'newt' now has the old hash */ 658 reinsert(L, &newt, t); /* 'newt' now has the old hash */
632 freehash(L, &newt); /* free old hash part */ 659 freehash(L, &newt); /* free old hash part */
@@ -682,8 +709,9 @@ Table *luaH_new (lua_State *L) {
682 709
683 710
684void luaH_free (lua_State *L, Table *t) { 711void luaH_free (lua_State *L, Table *t) {
712 unsigned ps = concretesize(luaH_realasize(t));
685 freehash(L, t); 713 freehash(L, t);
686 luaM_freearray(L, t->array, luaH_realasize(t)); 714 luaM_freearray(L, t->array, ps);
687 luaM_free(L, t); 715 luaM_free(L, t);
688} 716}
689 717
@@ -799,7 +827,7 @@ static int finishnodeget (const TValue *val, TValue *res) {
799 827
800int luaH_getint (Table *t, lua_Integer key, TValue *res) { 828int luaH_getint (Table *t, lua_Integer key, TValue *res) {
801 if (keyinarray(t, key)) { 829 if (keyinarray(t, key)) {
802 int tag = *getArrTag(t, key); 830 int tag = *getArrTag(t, key - 1);
803 if (!tagisempty(tag)) { 831 if (!tagisempty(tag)) {
804 farr2val(t, key, tag, res); 832 farr2val(t, key, tag, res);
805 return HOK; /* success */ 833 return HOK; /* success */
@@ -902,7 +930,7 @@ static int finishnodeset (Table *t, const TValue *slot, TValue *val) {
902 930
903int luaH_psetint (Table *t, lua_Integer key, TValue *val) { 931int luaH_psetint (Table *t, lua_Integer key, TValue *val) {
904 if (keyinarray(t, key)) { 932 if (keyinarray(t, key)) {
905 lu_byte *tag = getArrTag(t, key); 933 lu_byte *tag = getArrTag(t, key - 1);
906 if (!tagisempty(*tag)) { 934 if (!tagisempty(*tag)) {
907 fval2arr(t, key, tag, val); 935 fval2arr(t, key, tag, val);
908 return HOK; /* success */ 936 return HOK; /* success */
@@ -960,7 +988,7 @@ void luaH_finishset (lua_State *L, Table *t, const TValue *key,
960 } 988 }
961 else { /* array entry */ 989 else { /* array entry */
962 hres = ~hres; /* real index */ 990 hres = ~hres; /* real index */
963 fval2arr(t, hres, getArrTag(t, hres), value); 991 obj2arr(t, hres, value);
964 } 992 }
965} 993}
966 994
diff --git a/ltable.h b/ltable.h
index 371e721d..b401aba1 100644
--- a/ltable.h
+++ b/ltable.h
@@ -51,31 +51,68 @@
51*/ 51*/
52 52
53 53
54struct ArrayCell { 54/*
55 lu_byte tt; 55** The array part of a table is represented by an array of cells.
56** Each cell is composed of (NM + 1) elements, and each element has the
57** type 'ArrayCell'. In each cell, only one element has the variant
58** 'tag', while the other NM elements have the variant 'value'. The
59** array in the 'tag' element holds the tags of the other elements in
60** that cell.
61*/
62#define NM ((unsigned int)sizeof(Value))
63
64union ArrayCell {
65 unsigned char tag[NM];
56 Value value; 66 Value value;
57}; 67};
58 68
59 69
60/* fast access to components of array values */ 70/*
61#define getArrTag(t,k) (&(t)->array[k - 1].tt) 71** 'NMTag' defines which cell element has the tags; that could be any
62#define getArrVal(t,k) (&(t)->array[k - 1].value) 72** value between 0 (tags come before all values) and NM (tags come after
73** all values).
74*/
75#define NMTag 0
63 76
64#define tagisempty(tag) (novariant(tag) == LUA_TNIL)
65 77
78/*
79** Computes the concrete index that holds the tag of abstract index 'i'
80*/
81#define TagIndex(i) (((i)/NM * (NM + 1u)) + NMTag)
66 82
67#define farr2val(h,k,tag,res) \ 83/*
68 ((res)->tt_ = tag, (res)->value_ = *getArrVal(h,k)) 84** Computes the concrete index that holds the value of abstract index 'i'
85*/
86#define ValueIndex(i) ((i) + (((i) + (NM - NMTag))/NM))
69 87
70#define fval2arr(h,k,tag,val) \
71 (*tag = (val)->tt_, *getArrVal(h,k) = (val)->value_)
72 88
89/* Computes the address of the tag for the abstract index 'k' */
90#define getArrTag(t,k) (&(t)->array[TagIndex(k)].tag[(k)%NM])
73 91
74#define obj2arr(h,k,val) \ 92/* Computes the address of the value for the abstract index 'k' */
75 (*getArrTag(h,k) = (val)->tt_, *getArrVal(h,k) = (val)->value_) 93#define getArrVal(t,k) (&(t)->array[ValueIndex(k)].value)
76 94
95
96/*
97** Move TValues to/from arrays, using Lua indices
98*/
77#define arr2obj(h,k,val) \ 99#define arr2obj(h,k,val) \
78 ((val)->tt_ = *getArrTag(h,k), (val)->value_ = *getArrVal(h,k)) 100 ((val)->tt_ = *getArrTag(h,(k)-1u), (val)->value_ = *getArrVal(h,(k)-1u))
101
102#define obj2arr(h,k,val) \
103 (*getArrTag(h,(k)-1u) = (val)->tt_, *getArrVal(h,(k)-1u) = (val)->value_)
104
105
106/*
107** Often, we need to check the tag of a value before moving it. These
108** macros also move TValues to/from arrays, but receive the precomputed
109** tag value or address as an extra argument.
110*/
111#define farr2val(h,k,tag,res) \
112 ((res)->tt_ = tag, (res)->value_ = *getArrVal(h,(k)-1u))
113
114#define fval2arr(h,k,tag,val) \
115 (*tag = (val)->tt_, *getArrVal(h,(k)-1u) = (val)->value_)
79 116
80 117
81LUAI_FUNC int luaH_getshortstr (Table *t, TString *key, TValue *res); 118LUAI_FUNC int luaH_getshortstr (Table *t, TString *key, TValue *res);
diff --git a/lvm.h b/lvm.h
index 32455fba..c74c81f8 100644
--- a/lvm.h
+++ b/lvm.h
@@ -90,7 +90,7 @@ typedef enum {
90 if (!ttistable(t)) aux = HNOTATABLE; \ 90 if (!ttistable(t)) aux = HNOTATABLE; \
91 else { Table *h = hvalue(t); lua_Unsigned u = l_castS2U(k); \ 91 else { Table *h = hvalue(t); lua_Unsigned u = l_castS2U(k); \
92 if ((u - 1u < h->alimit)) { \ 92 if ((u - 1u < h->alimit)) { \
93 int tag = *getArrTag(h,u); \ 93 int tag = *getArrTag(h,(u)-1u); \
94 if (tagisempty(tag)) aux = HNOTFOUND; \ 94 if (tagisempty(tag)) aux = HNOTFOUND; \
95 else { farr2val(h, u, tag, res); aux = HOK; }} \ 95 else { farr2val(h, u, tag, res); aux = HOK; }} \
96 else { aux = luaH_getint(h, u, res); }} 96 else { aux = luaH_getint(h, u, res); }}
@@ -103,7 +103,7 @@ typedef enum {
103 if (!ttistable(t)) aux = HNOTATABLE; \ 103 if (!ttistable(t)) aux = HNOTATABLE; \
104 else { Table *h = hvalue(t); lua_Unsigned u = l_castS2U(k); \ 104 else { Table *h = hvalue(t); lua_Unsigned u = l_castS2U(k); \
105 if ((u - 1u < h->alimit)) { \ 105 if ((u - 1u < h->alimit)) { \
106 lu_byte *tag = getArrTag(h,u); \ 106 lu_byte *tag = getArrTag(h,(u)-1u); \
107 if (tagisempty(*tag)) aux = ~cast_int(u); \ 107 if (tagisempty(*tag)) aux = ~cast_int(u); \
108 else { fval2arr(h, u, tag, val); aux = HOK; }} \ 108 else { fval2arr(h, u, tag, val); aux = HOK; }} \
109 else { aux = luaH_psetint(h, u, val); }} 109 else { aux = luaH_psetint(h, u, val); }}