diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-11-24 14:41:07 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-11-24 14:41:07 -0300 |
commit | 52b899d60d8c61b8affe0206014173912de94940 (patch) | |
tree | 5e6f9116b2c70a5ebd4c1bdea49f283cca5cb3fb | |
parent | 25cd3d377ec13176a6701d9d21a278ba8f2bc3d6 (diff) | |
download | lua-52b899d60d8c61b8affe0206014173912de94940.tar.gz lua-52b899d60d8c61b8affe0206014173912de94940.tar.bz2 lua-52b899d60d8c61b8affe0206014173912de94940.zip |
Simpler coding for new representation for arrays
With the tags comming first in a cell, we can define the whole cell
as a C type and let C do part of the address computations.
-rw-r--r-- | lobject.h | 2 | ||||
-rw-r--r-- | ltable.c | 46 | ||||
-rw-r--r-- | ltable.h | 38 |
3 files changed, 36 insertions, 50 deletions
@@ -762,7 +762,7 @@ typedef union Node { | |||
762 | #define setnorealasize(t) ((t)->flags |= BITRAS) | 762 | #define setnorealasize(t) ((t)->flags |= BITRAS) |
763 | 763 | ||
764 | 764 | ||
765 | typedef union ArrayCell ArrayCell; | 765 | typedef struct ArrayCell ArrayCell; |
766 | 766 | ||
767 | 767 | ||
768 | typedef struct Table { | 768 | typedef struct Table { |
@@ -541,29 +541,28 @@ static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) { | |||
541 | 541 | ||
542 | 542 | ||
543 | /* | 543 | /* |
544 | ** Convert an "abstract size" (number of values in an array) to | 544 | ** Convert an "abstract size" (number of slots in an array) to |
545 | ** "concrete size" (number of cell elements in the array). Cells | 545 | ** "concrete size" (number of bytes in the array). |
546 | ** do not need to be full; we only must make sure it has the values | 546 | ** If the abstract size is not a multiple of NM, the last cell is |
547 | ** needed and its 'tag' element. So, we compute the concrete tag index | 547 | ** incomplete, so we don't need to allocate memory for the whole cell. |
548 | ** and the concrete value index of the last element, get their maximum | 548 | ** 'extra' computes how many values are not needed in that last cell. |
549 | ** and adds 1. | 549 | ** It will be zero when 'size' is a multiple of NM, and from there it |
550 | ** increases as 'size' decreases, up to (NM - 1). | ||
550 | */ | 551 | */ |
551 | static unsigned int concretesize (unsigned int size) { | 552 | static size_t concretesize (unsigned int size) { |
552 | if (size == 0) return 0; | 553 | unsigned int numcells = (size + NM - 1) / NM; /* (size / NM) rounded up */ |
553 | else { | 554 | unsigned int extra = NM - 1 - ((size + NM - 1) % NM); |
554 | unsigned int ts = TagIndex(size - 1); | 555 | return numcells * sizeof(ArrayCell) - extra * sizeof(Value); |
555 | unsigned int vs = ValueIndex(size - 1); | ||
556 | return ((ts >= vs) ? ts : vs) + 1; | ||
557 | } | ||
558 | } | 556 | } |
559 | 557 | ||
560 | 558 | ||
561 | static ArrayCell *resizearray (lua_State *L , Table *t, | 559 | static ArrayCell *resizearray (lua_State *L , Table *t, |
562 | unsigned int oldasize, | 560 | unsigned int oldasize, |
563 | unsigned int newasize) { | 561 | unsigned int newasize) { |
564 | oldasize = concretesize(oldasize); | 562 | size_t oldasizeb = concretesize(oldasize); |
565 | newasize = concretesize(newasize); | 563 | size_t newasizeb = concretesize(newasize); |
566 | return luaM_reallocvector(L, t->array, oldasize, newasize, ArrayCell); | 564 | void *a = luaM_reallocvector(L, t->array, oldasizeb, newasizeb, lu_byte); |
565 | return cast(ArrayCell*, a); | ||
567 | } | 566 | } |
568 | 567 | ||
569 | 568 | ||
@@ -747,10 +746,19 @@ Table *luaH_new (lua_State *L) { | |||
747 | } | 746 | } |
748 | 747 | ||
749 | 748 | ||
749 | /* | ||
750 | ** Frees a table. The assert ensures the correctness of 'concretesize', | ||
751 | ** checking its result against the address of the last element in the | ||
752 | ** array part of the table, computed abstractly. | ||
753 | */ | ||
750 | void luaH_free (lua_State *L, Table *t) { | 754 | void luaH_free (lua_State *L, Table *t) { |
751 | unsigned ps = concretesize(luaH_realasize(t)); | 755 | unsigned int realsize = luaH_realasize(t); |
756 | size_t sizeb = concretesize(realsize); | ||
757 | lua_assert((sizeb == 0 && realsize == 0) || | ||
758 | cast_charp(t->array) + sizeb - sizeof(Value) == | ||
759 | cast_charp(getArrVal(t, realsize - 1))); | ||
752 | freehash(L, t); | 760 | freehash(L, t); |
753 | luaM_freearray(L, t->array, ps); | 761 | luaM_freemem(L, t->array, sizeb); |
754 | luaM_free(L, t); | 762 | luaM_free(L, t); |
755 | } | 763 | } |
756 | 764 | ||
@@ -944,7 +952,7 @@ TString *luaH_getstrkey (Table *t, TString *key) { | |||
944 | ** main search function | 952 | ** main search function |
945 | */ | 953 | */ |
946 | int luaH_get (Table *t, const TValue *key, TValue *res) { | 954 | int luaH_get (Table *t, const TValue *key, TValue *res) { |
947 | const TValue *slot; | 955 | const TValue *slot; |
948 | switch (ttypetag(key)) { | 956 | switch (ttypetag(key)) { |
949 | case LUA_VSHRSTR: | 957 | case LUA_VSHRSTR: |
950 | slot = luaH_Hgetshortstr(t, tsvalue(key)); | 958 | slot = luaH_Hgetshortstr(t, tsvalue(key)); |
@@ -69,44 +69,22 @@ | |||
69 | 69 | ||
70 | /* | 70 | /* |
71 | ** The array part of a table is represented by an array of cells. | 71 | ** The array part of a table is represented by an array of cells. |
72 | ** Each cell is composed of (NM + 1) elements, and each element has the | 72 | ** Each cell is composed of NM tags followed by NM values, so that |
73 | ** type 'ArrayCell'. In each cell, only one element has the variant | 73 | ** no space is wasted in padding. |
74 | ** 'tag', while the other NM elements have the variant 'value'. The | ||
75 | ** array in the 'tag' element holds the tags of the other elements in | ||
76 | ** that cell. | ||
77 | */ | 74 | */ |
78 | #define NM ((unsigned int)sizeof(Value)) | 75 | #define NM cast_uint(sizeof(Value)) |
79 | 76 | ||
80 | union ArrayCell { | 77 | struct ArrayCell { |
81 | unsigned char tag[NM]; | 78 | lu_byte tag[NM]; |
82 | Value value; | 79 | Value value[NM]; |
83 | }; | 80 | }; |
84 | 81 | ||
85 | 82 | ||
86 | /* | ||
87 | ** 'NMTag' defines which cell element has the tags; that could be any | ||
88 | ** value between 0 (tags come before all values) and NM (tags come after | ||
89 | ** all values). | ||
90 | */ | ||
91 | #define NMTag 0 | ||
92 | |||
93 | |||
94 | /* | ||
95 | ** Computes the concrete index that holds the tag of abstract index 'i' | ||
96 | */ | ||
97 | #define TagIndex(i) (((i)/NM * (NM + 1u)) + NMTag) | ||
98 | |||
99 | /* | ||
100 | ** Computes the concrete index that holds the value of abstract index 'i' | ||
101 | */ | ||
102 | #define ValueIndex(i) ((i) + (((i) + (NM - NMTag))/NM)) | ||
103 | |||
104 | |||
105 | /* Computes the address of the tag for the abstract index 'k' */ | 83 | /* Computes the address of the tag for the abstract index 'k' */ |
106 | #define getArrTag(t,k) (&(t)->array[TagIndex(k)].tag[(k)%NM]) | 84 | #define getArrTag(t,k) (&(t)->array[(k)/NM].tag[(k)%NM]) |
107 | 85 | ||
108 | /* Computes the address of the value for the abstract index 'k' */ | 86 | /* Computes the address of the value for the abstract index 'k' */ |
109 | #define getArrVal(t,k) (&(t)->array[ValueIndex(k)].value) | 87 | #define getArrVal(t,k) (&(t)->array[(k)/NM].value[(k)%NM]) |
110 | 88 | ||
111 | 89 | ||
112 | /* | 90 | /* |