aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lobject.h5
-rw-r--r--ltable.c67
-rw-r--r--ltable.h37
3 files changed, 65 insertions, 44 deletions
diff --git a/lobject.h b/lobject.h
index 169512f8..a70731f7 100644
--- a/lobject.h
+++ b/lobject.h
@@ -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
776typedef struct ArrayCell ArrayCell;
777
778
779typedef struct Table { 776typedef 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;
diff --git a/ltable.c b/ltable.c
index ef19a5c5..e969adef 100644
--- a/ltable.c
+++ b/ltable.c
@@ -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*/
562static size_t concretesize (unsigned int size) { 558static 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
569static 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*/
575static 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*/
784void luaH_free (lua_State *L, Table *t) { 809void 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
diff --git a/ltable.h b/ltable.h
index 4734bd50..6db197ba 100644
--- a/ltable.h
+++ b/ltable.h
@@ -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
96struct 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))