aboutsummaryrefslogtreecommitdiff
path: root/ltable.c
diff options
context:
space:
mode:
Diffstat (limited to 'ltable.c')
-rw-r--r--ltable.c80
1 files changed, 65 insertions, 15 deletions
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 */