aboutsummaryrefslogtreecommitdiff
path: root/ltable.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--ltable.c80
1 files changed, 65 insertions, 15 deletions
diff --git a/ltable.c b/ltable.c
index 8c2bc3b2..c9f66b3c 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*/
@@ -370,8 +391,15 @@ int luaH_next (lua_State *L, Table *t, StkId key) {
370 391
371 392
372static void freehash (lua_State *L, Table *t) { 393static void freehash (lua_State *L, Table *t) {
373 if (!isdummy(t)) 394 if (!isdummy(t)) {
374 luaM_freearray(L, t->node, cast_sizet(sizenode(t))); 395 size_t bsize = sizenode(t) * sizeof(Node); /* 'node' size in bytes */
396 char *arr = cast_charp(t->node);
397 if (haslastfree(t)) {
398 bsize += sizeof(Limbox);
399 arr -= sizeof(Limbox);
400 }
401 luaM_freearray(L, arr, bsize);
402 }
375} 403}
376 404
377 405
@@ -550,7 +578,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
550 if (size == 0) { /* no elements to hash part? */ 578 if (size == 0) { /* no elements to hash part? */
551 t->node = cast(Node *, dummynode); /* use common 'dummynode' */ 579 t->node = cast(Node *, dummynode); /* use common 'dummynode' */
552 t->lsizenode = 0; 580 t->lsizenode = 0;
553 t->lastfree = NULL; /* signal that it is using dummy node */ 581 setdummy(t); /* signal that it is using dummy node */
554 } 582 }
555 else { 583 else {
556 int i; 584 int i;
@@ -558,15 +586,22 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
558 if (lsize > MAXHBITS || (1u << lsize) > MAXHSIZE) 586 if (lsize > MAXHBITS || (1u << lsize) > MAXHSIZE)
559 luaG_runerror(L, "table overflow"); 587 luaG_runerror(L, "table overflow");
560 size = twoto(lsize); 588 size = twoto(lsize);
561 t->node = luaM_newvector(L, size, Node); 589 if (lsize <= LLIMFORLAST) /* no 'lastfree' field? */
590 t->node = luaM_newvector(L, size, Node);
591 else {
592 size_t bsize = size * sizeof(Node) + sizeof(Limbox);
593 char *node = luaM_newblock(L, bsize);
594 t->node = cast(Node *, node + sizeof(Limbox));
595 *getlastfree(t) = size; /* all positions are free */
596 }
597 t->lsizenode = cast_byte(lsize);
598 setnodummy(t);
562 for (i = 0; i < cast_int(size); i++) { 599 for (i = 0; i < cast_int(size); i++) {
563 Node *n = gnode(t, i); 600 Node *n = gnode(t, i);
564 gnext(n) = 0; 601 gnext(n) = 0;
565 setnilkey(n); 602 setnilkey(n);
566 setempty(gval(n)); 603 setempty(gval(n));
567 } 604 }
568 t->lsizenode = cast_byte(lsize);
569 t->lastfree = gnode(t, size); /* all positions are free */
570 } 605 }
571} 606}
572 607
@@ -591,18 +626,21 @@ static void reinsert (lua_State *L, Table *ot, Table *t) {
591 626
592 627
593/* 628/*
594** Exchange the hash part of 't1' and 't2'. 629** Exchange the hash part of 't1' and 't2'. (In 'flags', only the
630** dummy bit must be exchanged: The 'isrealasize' is not related
631** to the hash part, and the metamethod bits do not change during
632** a resize, so the "real" table can keep their values.)
595*/ 633*/
596static void exchangehashpart (Table *t1, Table *t2) { 634static void exchangehashpart (Table *t1, Table *t2) {
597 lu_byte lsizenode = t1->lsizenode; 635 lu_byte lsizenode = t1->lsizenode;
598 Node *node = t1->node; 636 Node *node = t1->node;
599 Node *lastfree = t1->lastfree; 637 int bitdummy1 = t1->flags & BITDUMMY;
600 t1->lsizenode = t2->lsizenode; 638 t1->lsizenode = t2->lsizenode;
601 t1->node = t2->node; 639 t1->node = t2->node;
602 t1->lastfree = t2->lastfree; 640 t1->flags = (t1->flags & NOTBITDUMMY) | (t2->flags & BITDUMMY);
603 t2->lsizenode = lsizenode; 641 t2->lsizenode = lsizenode;
604 t2->node = node; 642 t2->node = node;
605 t2->lastfree = lastfree; 643 t2->flags = (t2->flags & NOTBITDUMMY) | bitdummy1;
606} 644}
607 645
608 646
@@ -626,6 +664,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize,
626 unsigned int oldasize = setlimittosize(t); 664 unsigned int oldasize = setlimittosize(t);
627 ArrayCell *newarray; 665 ArrayCell *newarray;
628 /* create new hash part with appropriate size into 'newt' */ 666 /* create new hash part with appropriate size into 'newt' */
667 newt.flags = 0;
629 setnodevector(L, &newt, nhsize); 668 setnodevector(L, &newt, nhsize);
630 if (newasize < oldasize) { /* will array shrink? */ 669 if (newasize < oldasize) { /* will array shrink? */
631 t->alimit = newasize; /* pretend array has new size... */ 670 t->alimit = newasize; /* pretend array has new size... */
@@ -717,11 +756,22 @@ void luaH_free (lua_State *L, Table *t) {
717 756
718 757
719static Node *getfreepos (Table *t) { 758static Node *getfreepos (Table *t) {
720 if (!isdummy(t)) { 759 if (haslastfree(t)) { /* does it have 'lastfree' information? */
721 while (t->lastfree > t->node) { 760 /* look for a spot before 'lastfree', updating 'lastfree' */
722 t->lastfree--; 761 while (*getlastfree(t) > 0) {
723 if (keyisnil(t->lastfree)) 762 Node *free = gnode(t, --(*getlastfree(t)));
724 return t->lastfree; 763 if (keyisnil(free))
764 return free;
765 }
766 }
767 else { /* no 'lastfree' information */
768 if (!isdummy(t)) {
769 int i = sizenode(t);
770 while (i--) { /* do a linear search */
771 Node *free = gnode(t, i);
772 if (keyisnil(free))
773 return free;
774 }
725 } 775 }
726 } 776 }
727 return NULL; /* could not find a free place */ 777 return NULL; /* could not find a free place */