diff options
| -rw-r--r-- | lobject.h | 5 | ||||
| -rw-r--r-- | ltable.c | 67 | ||||
| -rw-r--r-- | ltable.h | 37 |
3 files changed, 65 insertions, 44 deletions
| @@ -773,15 +773,12 @@ typedef union Node { | |||
| 773 | #define setnorealasize(t) ((t)->flags |= BITRAS) | 773 | #define setnorealasize(t) ((t)->flags |= BITRAS) |
| 774 | 774 | ||
| 775 | 775 | ||
| 776 | typedef struct ArrayCell ArrayCell; | ||
| 777 | |||
| 778 | |||
| 779 | typedef struct Table { | 776 | typedef struct Table { |
| 780 | CommonHeader; | 777 | CommonHeader; |
| 781 | lu_byte flags; /* 1<<p means tagmethod(p) is not present */ | 778 | lu_byte flags; /* 1<<p means tagmethod(p) is not present */ |
| 782 | lu_byte lsizenode; /* log2 of size of 'node' array */ | 779 | lu_byte lsizenode; /* log2 of size of 'node' array */ |
| 783 | unsigned int alimit; /* "limit" of 'array' array */ | 780 | unsigned int alimit; /* "limit" of 'array' array */ |
| 784 | ArrayCell *array; /* array part */ | 781 | Value *array; /* array part */ |
| 785 | Node *node; | 782 | Node *node; |
| 786 | struct Table *metatable; | 783 | struct Table *metatable; |
| 787 | GCObject *gclist; | 784 | GCObject *gclist; |
| @@ -25,6 +25,7 @@ | |||
| 25 | 25 | ||
| 26 | #include <math.h> | 26 | #include <math.h> |
| 27 | #include <limits.h> | 27 | #include <limits.h> |
| 28 | #include <string.h> | ||
| 28 | 29 | ||
| 29 | #include "lua.h" | 30 | #include "lua.h" |
| 30 | 31 | ||
| @@ -73,7 +74,7 @@ typedef union { | |||
| 73 | ** MAXASIZEB is the maximum number of elements in the array part such | 74 | ** MAXASIZEB is the maximum number of elements in the array part such |
| 74 | ** that the size of the array fits in 'size_t'. | 75 | ** that the size of the array fits in 'size_t'. |
| 75 | */ | 76 | */ |
| 76 | #define MAXASIZEB ((MAX_SIZET/sizeof(ArrayCell)) * NM) | 77 | #define MAXASIZEB (MAX_SIZET/(sizeof(Value) + 1)) |
| 77 | 78 | ||
| 78 | 79 | ||
| 79 | /* | 80 | /* |
| @@ -553,26 +554,52 @@ static int numusehash (const Table *t, unsigned *nums, unsigned *pna) { | |||
| 553 | /* | 554 | /* |
| 554 | ** Convert an "abstract size" (number of slots in an array) to | 555 | ** Convert an "abstract size" (number of slots in an array) to |
| 555 | ** "concrete size" (number of bytes in the array). | 556 | ** "concrete size" (number of bytes in the array). |
| 556 | ** If the abstract size is not a multiple of NM, the last cell is | ||
| 557 | ** incomplete, so we don't need to allocate memory for the whole cell. | ||
| 558 | ** 'extra' computes how many values are not needed in that last cell. | ||
| 559 | ** It will be zero when 'size' is a multiple of NM, and from there it | ||
| 560 | ** increases as 'size' decreases, up to (NM - 1). | ||
| 561 | */ | 557 | */ |
| 562 | static size_t concretesize (unsigned int size) { | 558 | static size_t concretesize (unsigned int size) { |
| 563 | unsigned int numcells = (size + NM - 1) / NM; /* (size / NM) rounded up */ | 559 | return size * sizeof(Value) + size; /* space for the two arrays */ |
| 564 | unsigned int extra = NM - 1 - ((size + NM - 1) % NM); | ||
| 565 | return numcells * sizeof(ArrayCell) - extra * sizeof(Value); | ||
| 566 | } | 560 | } |
| 567 | 561 | ||
| 568 | 562 | ||
| 569 | static ArrayCell *resizearray (lua_State *L , Table *t, | 563 | /* |
| 564 | ** Resize the array part of a table. If new size is equal to the old, | ||
| 565 | ** do nothing. Else, if new size is zero, free the old array. (It must | ||
| 566 | ** be present, as the sizes are different.) Otherwise, allocate a new | ||
| 567 | ** array, move the common elements to new proper position, and then | ||
| 568 | ** frees old array. | ||
| 569 | ** When array grows, we could reallocate it, but we still would need | ||
| 570 | ** to move the elements to their new position, so the copy implicit | ||
| 571 | ** in realloc is a waste. When array shrinks, it always erases some | ||
| 572 | ** elements that should still be in the array, so we must reallocate in | ||
| 573 | ** two steps anyway. It is simpler to always reallocate in two steps. | ||
| 574 | */ | ||
| 575 | static Value *resizearray (lua_State *L , Table *t, | ||
| 570 | unsigned oldasize, | 576 | unsigned oldasize, |
| 571 | unsigned newasize) { | 577 | unsigned newasize) { |
| 572 | size_t oldasizeb = concretesize(oldasize); | 578 | if (oldasize == newasize) |
| 573 | size_t newasizeb = concretesize(newasize); | 579 | return t->array; /* nothing to be done */ |
| 574 | void *a = luaM_reallocvector(L, t->array, oldasizeb, newasizeb, lu_byte); | 580 | else if (newasize == 0) { /* erasing array? */ |
| 575 | return cast(ArrayCell*, a); | 581 | Value *op = t->array - oldasize; /* original array's real address */ |
| 582 | luaM_freemem(L, op, concretesize(oldasize)); /* free it */ | ||
| 583 | return NULL; | ||
| 584 | } | ||
| 585 | else { | ||
| 586 | size_t newasizeb = concretesize(newasize); | ||
| 587 | Value *np = cast(Value *, | ||
| 588 | luaM_reallocvector(L, NULL, 0, newasizeb, lu_byte)); | ||
| 589 | if (np == NULL) /* allocation error? */ | ||
| 590 | return NULL; | ||
| 591 | if (oldasize > 0) { | ||
| 592 | Value *op = t->array - oldasize; /* real original array */ | ||
| 593 | unsigned tomove = (oldasize < newasize) ? oldasize : newasize; | ||
| 594 | lua_assert(tomove > 0); | ||
| 595 | /* move common elements to new position */ | ||
| 596 | memcpy(np + newasize - tomove, | ||
| 597 | op + oldasize - tomove, | ||
| 598 | concretesize(tomove)); | ||
| 599 | luaM_freemem(L, op, concretesize(oldasize)); | ||
| 600 | } | ||
| 601 | return np + newasize; /* shift pointer to the end of value segment */ | ||
| 602 | } | ||
| 576 | } | 603 | } |
| 577 | 604 | ||
| 578 | 605 | ||
| @@ -699,7 +726,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned newasize, | |||
| 699 | unsigned nhsize) { | 726 | unsigned nhsize) { |
| 700 | Table newt; /* to keep the new hash part */ | 727 | Table newt; /* to keep the new hash part */ |
| 701 | unsigned int oldasize = setlimittosize(t); | 728 | unsigned int oldasize = setlimittosize(t); |
| 702 | ArrayCell *newarray; | 729 | Value *newarray; |
| 703 | if (newasize > MAXASIZE) | 730 | if (newasize > MAXASIZE) |
| 704 | luaG_runerror(L, "table overflow"); | 731 | luaG_runerror(L, "table overflow"); |
| 705 | /* create new hash part with appropriate size into 'newt' */ | 732 | /* create new hash part with appropriate size into 'newt' */ |
| @@ -777,18 +804,12 @@ Table *luaH_new (lua_State *L) { | |||
| 777 | 804 | ||
| 778 | 805 | ||
| 779 | /* | 806 | /* |
| 780 | ** Frees a table. The assert ensures the correctness of 'concretesize', | 807 | ** Frees a table. |
| 781 | ** checking its result against the address of the last element in the | ||
| 782 | ** array part of the table, computed abstractly. | ||
| 783 | */ | 808 | */ |
| 784 | void luaH_free (lua_State *L, Table *t) { | 809 | void luaH_free (lua_State *L, Table *t) { |
| 785 | unsigned int realsize = luaH_realasize(t); | 810 | unsigned int realsize = luaH_realasize(t); |
| 786 | size_t sizeb = concretesize(realsize); | ||
| 787 | lua_assert((sizeb == 0 && realsize == 0) || | ||
| 788 | cast_charp(t->array) + sizeb - sizeof(Value) == | ||
| 789 | cast_charp(getArrVal(t, realsize - 1))); | ||
| 790 | freehash(L, t); | 811 | freehash(L, t); |
| 791 | luaM_freemem(L, t->array, sizeb); | 812 | resizearray(L, t, realsize, 0); |
| 792 | luaM_free(L, t); | 813 | luaM_free(L, t); |
| 793 | } | 814 | } |
| 794 | 815 | ||
| @@ -71,7 +71,7 @@ | |||
| 71 | 71 | ||
| 72 | /* | 72 | /* |
| 73 | ** 'luaH_get*' operations set 'res', unless the value is absent, and | 73 | ** 'luaH_get*' operations set 'res', unless the value is absent, and |
| 74 | ** return the tag of the result, | 74 | ** return the tag of the result. |
| 75 | ** The 'luaH_pset*' (pre-set) operations set the given value and return | 75 | ** The 'luaH_pset*' (pre-set) operations set the given value and return |
| 76 | ** HOK, unless the original value is absent. In that case, if the key | 76 | ** HOK, unless the original value is absent. In that case, if the key |
| 77 | ** is really absent, they return HNOTFOUND. Otherwise, if there is a | 77 | ** is really absent, they return HNOTFOUND. Otherwise, if there is a |
| @@ -86,24 +86,27 @@ | |||
| 86 | 86 | ||
| 87 | 87 | ||
| 88 | /* | 88 | /* |
| 89 | ** The array part of a table is represented by an array of cells. | 89 | ** The array part of a table is represented by an inverted array of |
| 90 | ** Each cell is composed of NM tags followed by NM values, so that | 90 | ** values followed by an array of tags, to avoid wasting space with |
| 91 | ** no space is wasted in padding. The last cell may be incomplete, | 91 | ** padding. The 'array' pointer points to the junction of the two |
| 92 | ** that is, it may have fewer than NM values. | 92 | ** arrays, so that values are indexed with negative indices and tags |
| 93 | ** with non-negative indices. | ||
| 94 | |||
| 95 | Values Tags | ||
| 96 | -------------------------------------------------------- | ||
| 97 | ... | Value 1 | Value 0 |0|1|... | ||
| 98 | -------------------------------------------------------- | ||
| 99 | ^ t->array | ||
| 100 | |||
| 101 | ** All accesses to 't->array' should be through the macros 'getArrTag' | ||
| 102 | ** and 'getArrVal'. | ||
| 93 | */ | 103 | */ |
| 94 | #define NM cast_uint(sizeof(Value)) | ||
| 95 | |||
| 96 | struct ArrayCell { | ||
| 97 | lu_byte tag[NM]; | ||
| 98 | Value value[NM]; | ||
| 99 | }; | ||
| 100 | |||
| 101 | 104 | ||
| 102 | /* Computes the address of the tag for the abstract index 'k' */ | 105 | /* Computes the address of the tag for the abstract index 'k' */ |
| 103 | #define getArrTag(t,k) (&(t)->array[(k)/NM].tag[(k)%NM]) | 106 | #define getArrTag(t,k) (cast(lu_byte*, (t)->array) + (k)) |
| 104 | 107 | ||
| 105 | /* Computes the address of the value for the abstract index 'k' */ | 108 | /* Computes the address of the value for the abstract index 'k' */ |
| 106 | #define getArrVal(t,k) (&(t)->array[(k)/NM].value[(k)%NM]) | 109 | #define getArrVal(t,k) ((t)->array - 1 - (k)) |
| 107 | 110 | ||
| 108 | 111 | ||
| 109 | /* | 112 | /* |
| @@ -117,9 +120,9 @@ struct ArrayCell { | |||
| 117 | 120 | ||
| 118 | 121 | ||
| 119 | /* | 122 | /* |
| 120 | ** Often, we need to check the tag of a value before moving it. These | 123 | ** Often, we need to check the tag of a value before moving it. The |
| 121 | ** macros also move TValues to/from arrays, but receive the precomputed | 124 | ** following macros also move TValues to/from arrays, but receive the |
| 122 | ** tag value or address as an extra argument. | 125 | ** precomputed tag value or address as an extra argument. |
| 123 | */ | 126 | */ |
| 124 | #define farr2val(h,k,tag,res) \ | 127 | #define farr2val(h,k,tag,res) \ |
| 125 | ((res)->tt_ = tag, (res)->value_ = *getArrVal(h,(k)-1u)) | 128 | ((res)->tt_ = tag, (res)->value_ = *getArrVal(h,(k)-1u)) |
