diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-11-03 15:26:13 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-11-03 15:26:13 -0300 |
commit | 08a077d673b25cf1fbfe21794f240f4ff4999667 (patch) | |
tree | 77ae945c9a2680af23d5fa11c156482b35c14e04 | |
parent | 43c8e5bded052801f54a7439d18933b83570eb82 (diff) | |
download | lua-08a077d673b25cf1fbfe21794f240f4ff4999667.tar.gz lua-08a077d673b25cf1fbfe21794f240f4ff4999667.tar.bz2 lua-08a077d673b25cf1fbfe21794f240f4ff4999667.zip |
Full implementation of new representation for arrays
Diffstat (limited to '')
-rw-r--r-- | lgc.c | 8 | ||||
-rw-r--r-- | lobject.h | 4 | ||||
-rw-r--r-- | ltable.c | 46 | ||||
-rw-r--r-- | ltable.h | 63 | ||||
-rw-r--r-- | lvm.h | 4 |
5 files changed, 96 insertions, 29 deletions
@@ -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? */ |
@@ -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 | ||
739 | typedef struct ArrayCell ArrayCell; | 741 | typedef union ArrayCell ArrayCell; |
740 | 742 | ||
741 | 743 | ||
742 | typedef struct Table { | 744 | typedef struct Table { |
@@ -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 | ||
460 | l_sinline int arraykeyisempty (const Table *t, lua_Integer key) { | 460 | l_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 | */ | ||
523 | static 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 | |||
533 | static 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 | ||
684 | void luaH_free (lua_State *L, Table *t) { | 711 | void 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 | ||
800 | int luaH_getint (Table *t, lua_Integer key, TValue *res) { | 828 | int 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 | ||
903 | int luaH_psetint (Table *t, lua_Integer key, TValue *val) { | 931 | int 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 | ||
@@ -51,31 +51,68 @@ | |||
51 | */ | 51 | */ |
52 | 52 | ||
53 | 53 | ||
54 | struct 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 | |||
64 | union 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 | ||
81 | LUAI_FUNC int luaH_getshortstr (Table *t, TString *key, TValue *res); | 118 | LUAI_FUNC int luaH_getshortstr (Table *t, TString *key, TValue *res); |
@@ -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); }} |