aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lmem.h2
-rw-r--r--lobject.h1
-rw-r--r--ltable.c80
-rw-r--r--ltable.h14
-rw-r--r--ltests.c3
-rw-r--r--ltm.h4
-rw-r--r--testes/nextvar.lua4
7 files changed, 84 insertions, 24 deletions
diff --git a/lmem.h b/lmem.h
index 8c75a44b..c5dada9c 100644
--- a/lmem.h
+++ b/lmem.h
@@ -63,6 +63,8 @@
63 63
64#define luaM_newobject(L,tag,s) luaM_malloc_(L, (s), tag) 64#define luaM_newobject(L,tag,s) luaM_malloc_(L, (s), tag)
65 65
66#define luaM_newblock(L, size) luaM_newvector(L, size, char)
67
66#define luaM_growvector(L,v,nelems,size,t,limit,e) \ 68#define luaM_growvector(L,v,nelems,size,t,limit,e) \
67 ((v)=cast(t *, luaM_growaux_(L,v,nelems,&(size),sizeof(t), \ 69 ((v)=cast(t *, luaM_growaux_(L,v,nelems,&(size),sizeof(t), \
68 luaM_limitN(limit,t),e))) 70 luaM_limitN(limit,t),e)))
diff --git a/lobject.h b/lobject.h
index e7f58cbd..74a6fd1e 100644
--- a/lobject.h
+++ b/lobject.h
@@ -744,7 +744,6 @@ typedef struct Table {
744 unsigned int alimit; /* "limit" of 'array' array */ 744 unsigned int alimit; /* "limit" of 'array' array */
745 TValue *array; /* array part */ 745 TValue *array; /* array part */
746 Node *node; 746 Node *node;
747 Node *lastfree; /* any free position is before this position */
748 struct Table *metatable; 747 struct Table *metatable;
749 GCObject *gclist; 748 GCObject *gclist;
750} Table; 749} Table;
diff --git a/ltable.c b/ltable.c
index cc7993e0..485563f3 100644
--- a/ltable.c
+++ b/ltable.c
@@ -40,6 +40,27 @@
40 40
41 41
42/* 42/*
43** Only tables with hash parts larget than LIMFORLAST has a 'lastfree'
44** field that optimizes finding a free slot. Smaller tables do a
45** complete search when looking for a free slot.
46*/
47#define LLIMFORLAST 2 /* log2 of LIMTFORLAST */
48#define LIMFORLAST twoto(LLIMFORLAST)
49
50/*
51** Union to store an int field ensuring that what follows it in
52** memory is properly aligned to store a TValue.
53*/
54typedef union {
55 int lastfree;
56 char padding[offsetof(struct { int i; TValue v; }, v)];
57} Limbox;
58
59#define haslastfree(t) ((t)->lsizenode > LLIMFORLAST)
60#define getlastfree(t) (&((cast(Limbox *, (t)->node) - 1)->lastfree))
61
62
63/*
43** MAXABITS is the largest integer such that MAXASIZE fits in an 64** MAXABITS is the largest integer such that MAXASIZE fits in an
44** unsigned int. 65** unsigned int.
45*/ 66*/
@@ -367,8 +388,15 @@ int luaH_next (lua_State *L, Table *t, StkId key) {
367 388
368 389
369static void freehash (lua_State *L, Table *t) { 390static void freehash (lua_State *L, Table *t) {
370 if (!isdummy(t)) 391 if (!isdummy(t)) {
371 luaM_freearray(L, t->node, cast_sizet(sizenode(t))); 392 size_t bsize = sizenode(t) * sizeof(Node); /* 'node' size in bytes */
393 char *arr = cast_charp(t->node);
394 if (haslastfree(t)) {
395 bsize += sizeof(Limbox);
396 arr -= sizeof(Limbox);
397 }
398 luaM_freearray(L, arr, bsize);
399 }
372} 400}
373 401
374 402
@@ -479,7 +507,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
479 if (size == 0) { /* no elements to hash part? */ 507 if (size == 0) { /* no elements to hash part? */
480 t->node = cast(Node *, dummynode); /* use common 'dummynode' */ 508 t->node = cast(Node *, dummynode); /* use common 'dummynode' */
481 t->lsizenode = 0; 509 t->lsizenode = 0;
482 t->lastfree = NULL; /* signal that it is using dummy node */ 510 setdummy(t); /* signal that it is using dummy node */
483 } 511 }
484 else { 512 else {
485 int i; 513 int i;
@@ -487,15 +515,22 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
487 if (lsize > MAXHBITS || (1u << lsize) > MAXHSIZE) 515 if (lsize > MAXHBITS || (1u << lsize) > MAXHSIZE)
488 luaG_runerror(L, "table overflow"); 516 luaG_runerror(L, "table overflow");
489 size = twoto(lsize); 517 size = twoto(lsize);
490 t->node = luaM_newvector(L, size, Node); 518 if (lsize <= LLIMFORLAST) /* no 'lastfree' field? */
519 t->node = luaM_newvector(L, size, Node);
520 else {
521 size_t bsize = size * sizeof(Node) + sizeof(Limbox);
522 char *node = luaM_newblock(L, bsize);
523 t->node = cast(Node *, node + sizeof(Limbox));
524 *getlastfree(t) = size; /* all positions are free */
525 }
526 t->lsizenode = cast_byte(lsize);
527 setnodummy(t);
491 for (i = 0; i < cast_int(size); i++) { 528 for (i = 0; i < cast_int(size); i++) {
492 Node *n = gnode(t, i); 529 Node *n = gnode(t, i);
493 gnext(n) = 0; 530 gnext(n) = 0;
494 setnilkey(n); 531 setnilkey(n);
495 setempty(gval(n)); 532 setempty(gval(n));
496 } 533 }
497 t->lsizenode = cast_byte(lsize);
498 t->lastfree = gnode(t, size); /* all positions are free */
499 } 534 }
500} 535}
501 536
@@ -520,18 +555,21 @@ static void reinsert (lua_State *L, Table *ot, Table *t) {
520 555
521 556
522/* 557/*
523** Exchange the hash part of 't1' and 't2'. 558** Exchange the hash part of 't1' and 't2'. (In 'flags', only the
559** dummy bit must be exchanged: The 'isrealasize' is not related
560** to the hash part, and the metamethod bits do not change during
561** a resize, so the "real" table can keep their values.)
524*/ 562*/
525static void exchangehashpart (Table *t1, Table *t2) { 563static void exchangehashpart (Table *t1, Table *t2) {
526 lu_byte lsizenode = t1->lsizenode; 564 lu_byte lsizenode = t1->lsizenode;
527 Node *node = t1->node; 565 Node *node = t1->node;
528 Node *lastfree = t1->lastfree; 566 int bitdummy1 = t1->flags & BITDUMMY;
529 t1->lsizenode = t2->lsizenode; 567 t1->lsizenode = t2->lsizenode;
530 t1->node = t2->node; 568 t1->node = t2->node;
531 t1->lastfree = t2->lastfree; 569 t1->flags = (t1->flags & NOTBITDUMMY) | (t2->flags & BITDUMMY);
532 t2->lsizenode = lsizenode; 570 t2->lsizenode = lsizenode;
533 t2->node = node; 571 t2->node = node;
534 t2->lastfree = lastfree; 572 t2->flags = (t2->flags & NOTBITDUMMY) | bitdummy1;
535} 573}
536 574
537 575
@@ -555,6 +593,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize,
555 unsigned int oldasize = setlimittosize(t); 593 unsigned int oldasize = setlimittosize(t);
556 TValue *newarray; 594 TValue *newarray;
557 /* create new hash part with appropriate size into 'newt' */ 595 /* create new hash part with appropriate size into 'newt' */
596 newt.flags = 0;
558 setnodevector(L, &newt, nhsize); 597 setnodevector(L, &newt, nhsize);
559 if (newasize < oldasize) { /* will array shrink? */ 598 if (newasize < oldasize) { /* will array shrink? */
560 t->alimit = newasize; /* pretend array has new size... */ 599 t->alimit = newasize; /* pretend array has new size... */
@@ -641,11 +680,22 @@ void luaH_free (lua_State *L, Table *t) {
641 680
642 681
643static Node *getfreepos (Table *t) { 682static Node *getfreepos (Table *t) {
644 if (!isdummy(t)) { 683 if (haslastfree(t)) { /* does it have 'lastfree' information? */
645 while (t->lastfree > t->node) { 684 /* look for a spot before 'lastfree', updating 'lastfree' */
646 t->lastfree--; 685 while (*getlastfree(t) > 0) {
647 if (keyisnil(t->lastfree)) 686 Node *free = gnode(t, --(*getlastfree(t)));
648 return t->lastfree; 687 if (keyisnil(free))
688 return free;
689 }
690 }
691 else { /* no 'lastfree' information */
692 if (!isdummy(t)) {
693 int i = sizenode(t);
694 while (i--) { /* do a linear search */
695 Node *free = gnode(t, i);
696 if (keyisnil(free))
697 return free;
698 }
649 } 699 }
650 } 700 }
651 return NULL; /* could not find a free place */ 701 return NULL; /* could not find a free place */
diff --git a/ltable.h b/ltable.h
index 75dd9e26..dce8c2f7 100644
--- a/ltable.h
+++ b/ltable.h
@@ -23,8 +23,18 @@
23#define invalidateTMcache(t) ((t)->flags &= ~maskflags) 23#define invalidateTMcache(t) ((t)->flags &= ~maskflags)
24 24
25 25
26/* true when 't' is using 'dummynode' as its hash part */ 26/*
27#define isdummy(t) ((t)->lastfree == NULL) 27** Bit BITDUMMY set in 'flags' means the table is using the dummy node
28** for its hash part.
29*/
30
31#define BITDUMMY (1 << 6)
32#define NOTBITDUMMY cast_byte(~BITDUMMY)
33#define isdummy(t) ((t)->flags & BITDUMMY)
34
35#define setnodummy(t) ((t)->flags &= NOTBITDUMMY)
36#define setdummy(t) ((t)->flags |= BITDUMMY)
37
28 38
29 39
30/* allocated size for hash nodes */ 40/* allocated size for hash nodes */
diff --git a/ltests.c b/ltests.c
index 4a0a6af1..1caed04c 100644
--- a/ltests.c
+++ b/ltests.c
@@ -999,9 +999,8 @@ static int table_query (lua_State *L) {
999 if (i == -1) { 999 if (i == -1) {
1000 lua_pushinteger(L, asize); 1000 lua_pushinteger(L, asize);
1001 lua_pushinteger(L, allocsizenode(t)); 1001 lua_pushinteger(L, allocsizenode(t));
1002 lua_pushinteger(L, isdummy(t) ? 0 : t->lastfree - t->node);
1003 lua_pushinteger(L, t->alimit); 1002 lua_pushinteger(L, t->alimit);
1004 return 4; 1003 return 3;
1005 } 1004 }
1006 else if ((unsigned int)i < asize) { 1005 else if ((unsigned int)i < asize) {
1007 lua_pushinteger(L, i); 1006 lua_pushinteger(L, i);
diff --git a/ltm.h b/ltm.h
index 73b833c6..f3872655 100644
--- a/ltm.h
+++ b/ltm.h
@@ -48,8 +48,8 @@ typedef enum {
48/* 48/*
49** Mask with 1 in all fast-access methods. A 1 in any of these bits 49** Mask with 1 in all fast-access methods. A 1 in any of these bits
50** in the flag of a (meta)table means the metatable does not have the 50** in the flag of a (meta)table means the metatable does not have the
51** corresponding metamethod field. (Bit 7 of the flag is used for 51** corresponding metamethod field. (Bit 6 of the flag indicates that
52** 'isrealasize'.) 52** the table is using the dummy node; bit 7 is used for 'isrealasize'.)
53*/ 53*/
54#define maskflags (~(~0u << (TM_EQ + 1))) 54#define maskflags (~(~0u << (TM_EQ + 1)))
55 55
diff --git a/testes/nextvar.lua b/testes/nextvar.lua
index 0874e5bb..80b3d05c 100644
--- a/testes/nextvar.lua
+++ b/testes/nextvar.lua
@@ -210,9 +210,9 @@ assert(T.querytab(a) == 64) -- array part has 64 elements
210a[32] = true; a[48] = true; -- binary search will find these ones 210a[32] = true; a[48] = true; -- binary search will find these ones
211a[51] = true -- binary search will miss this one 211a[51] = true -- binary search will miss this one
212assert(#a == 48) -- this will set the limit 212assert(#a == 48) -- this will set the limit
213assert(select(4, T.querytab(a)) == 48) -- this is the limit now 213assert(select(3, T.querytab(a)) == 48) -- this is the limit now
214a[50] = true -- this will set a new limit 214a[50] = true -- this will set a new limit
215assert(select(4, T.querytab(a)) == 50) -- this is the limit now 215assert(select(3, T.querytab(a)) == 50) -- this is the limit now
216-- but the size is larger (and still inside the array part) 216-- but the size is larger (and still inside the array part)
217assert(#a == 51) 217assert(#a == 51)
218 218