aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--lgc.c59
-rw-r--r--ltable.c57
-rw-r--r--ltable.h18
3 files changed, 99 insertions, 35 deletions
diff --git a/lgc.c b/lgc.c
index f813038f..f76e851e 100644
--- a/lgc.c
+++ b/lgc.c
@@ -465,6 +465,46 @@ static void traverseweakvalue (global_State *g, Table *h) {
465} 465}
466 466
467 467
468#define BK2(x) cast(lua_Unsigned, ((x) << 8) | BIT_ISCOLLECTABLE)
469/*
470** Check whether some value in the cell starting at index 'i'
471** is collectable
472*/
473static int checkBulkCollectable (Table *h, unsigned i) {
474 const lua_Unsigned bitscoll = BK2(BK2(BK2(BK2(BK2(BK2(BK2(BK2(~0u))))))));
475 int j;
476 i /= NM;
477 for (j = 0; j < BKSZ; j++) {
478 if (h->array[i].u.bulk[j] & bitscoll)
479 return 1;
480 }
481 return 0;
482}
483
484
485/*
486** Traverse the array part of a table. The traversal is made by cells,
487** only traversing a cell if it has some collectable tag among its tags.
488*/
489static int traversearray (global_State *g, Table *h) {
490 unsigned asize = luaH_realasize(h);
491 int marked = 0; /* true if some object is marked in this traversal */
492 unsigned i;
493 for (i = 0; i < asize; i += NM) { /* traverse array in cells */
494 if (checkBulkCollectable(h, i)) { /* something to mark in this cell? */
495 unsigned j;
496 for (j = 0; j < NM && i + j < asize; j++) {
497 GCObject *o = gcvalarr(h, i + j);
498 if (o != NULL && iswhite(o)) {
499 marked = 1;
500 reallymarkobject(g, o);
501 }
502 }
503 }
504 }
505 return marked;
506}
507
468/* 508/*
469** Traverse an ephemeron table and link it to proper list. Returns true 509** Traverse an ephemeron table and link it to proper list. Returns true
470** iff any object was marked during this traversal (which implies that 510** iff any object was marked during this traversal (which implies that
@@ -478,20 +518,11 @@ static void traverseweakvalue (global_State *g, Table *h) {
478** by 'genlink'. 518** by 'genlink'.
479*/ 519*/
480static int traverseephemeron (global_State *g, Table *h, int inv) { 520static int traverseephemeron (global_State *g, Table *h, int inv) {
481 int marked = 0; /* true if an object is marked in this traversal */
482 int hasclears = 0; /* true if table has white keys */ 521 int hasclears = 0; /* true if table has white keys */
483 int hasww = 0; /* true if table has entry "white-key -> white-value" */ 522 int hasww = 0; /* true if table has entry "white-key -> white-value" */
484 unsigned int i; 523 unsigned int i;
485 unsigned int asize = luaH_realasize(h);
486 unsigned int nsize = sizenode(h); 524 unsigned int nsize = sizenode(h);
487 /* traverse array part */ 525 int marked = traversearray(g, h); /* traverse array part */
488 for (i = 0; i < asize; i++) {
489 GCObject *o = gcvalarr(h, i);
490 if (o != NULL && iswhite(o)) {
491 marked = 1;
492 reallymarkobject(g, o);
493 }
494 }
495 /* traverse hash part; if 'inv', traverse descending 526 /* traverse hash part; if 'inv', traverse descending
496 (see 'convergeephemerons') */ 527 (see 'convergeephemerons') */
497 for (i = 0; i < nsize; i++) { 528 for (i = 0; i < nsize; i++) {
@@ -523,13 +554,7 @@ static int traverseephemeron (global_State *g, Table *h, int inv) {
523 554
524static void traversestrongtable (global_State *g, Table *h) { 555static void traversestrongtable (global_State *g, Table *h) {
525 Node *n, *limit = gnodelast(h); 556 Node *n, *limit = gnodelast(h);
526 unsigned int i; 557 traversearray(g, h);
527 unsigned int asize = luaH_realasize(h);
528 for (i = 0; i < asize; i++) { /* traverse array part */
529 GCObject *o = gcvalarr(h, i);
530 if (o != NULL && iswhite(o))
531 reallymarkobject(g, o);
532 }
533 for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ 558 for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */
534 if (isempty(gval(n))) /* entry is empty? */ 559 if (isempty(gval(n))) /* entry is empty? */
535 clearkey(n); /* clear its key */ 560 clearkey(n); /* clear its key */
diff --git a/ltable.c b/ltable.c
index cb7eb648..6eb5f3e3 100644
--- a/ltable.c
+++ b/ltable.c
@@ -654,6 +654,44 @@ static void exchangehashpart (Table *t1, Table *t2) {
654 654
655 655
656/* 656/*
657** Re-insert into the new hash part of a table the elements from the
658** vanishing slice of the array part.
659*/
660static void reinsertOldSlice (lua_State *L, Table *t, unsigned oldasize,
661 unsigned newasize) {
662 unsigned i;
663 t->alimit = newasize; /* pretend array has new size... */
664 for (i = newasize; i < oldasize; i++) { /* traverse vanishing slice */
665 int tag = *getArrTag(t, i);
666 if (!tagisempty(tag)) { /* a non-empty entry? */
667 TValue aux;
668 farr2val(t, i + 1, tag, &aux);
669 luaH_setint(L, t, i + 1, &aux); /* re-insert it into the table */
670 }
671 }
672 t->alimit = oldasize; /* restore current size... */
673}
674
675
676#define BK1(x) cast(lua_Unsigned, ((x) << 8) | LUA_VEMPTY)
677
678/*
679** Clear new slice of the array, in bulk.
680*/
681static void clearNewSlice (Table *t, unsigned oldasize, unsigned newasize) {
682 int i, j;
683 int firstcell = (oldasize + NM - 1) / NM;
684 int lastcell = cast_int((newasize + NM - 1) / NM) - 1;
685 for (i = firstcell; i <= lastcell; i++) {
686 /* empty tag repeated for all tags in a word */
687 const lua_Unsigned empty = BK1(BK1(BK1(BK1(BK1(BK1(BK1(BK1(0))))))));
688 for (j = 0; j < BKSZ; j++)
689 t->array[i].u.bulk[j] = empty;
690 }
691}
692
693
694/*
657** Resize table 't' for the new given sizes. Both allocations (for 695** Resize table 't' for the new given sizes. Both allocations (for
658** the hash part and for the array part) can fail, which creates some 696** the hash part and for the array part) can fail, which creates some
659** subtleties. If the first allocation, for the hash part, fails, an 697** subtleties. If the first allocation, for the hash part, fails, an
@@ -668,7 +706,6 @@ static void exchangehashpart (Table *t1, Table *t2) {
668*/ 706*/
669void luaH_resize (lua_State *L, Table *t, unsigned int newasize, 707void luaH_resize (lua_State *L, Table *t, unsigned int newasize,
670 unsigned int nhsize) { 708 unsigned int nhsize) {
671 unsigned int i;
672 Table newt; /* to keep the new hash part */ 709 Table newt; /* to keep the new hash part */
673 unsigned int oldasize = setlimittosize(t); 710 unsigned int oldasize = setlimittosize(t);
674 ArrayCell *newarray; 711 ArrayCell *newarray;
@@ -678,19 +715,10 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize,
678 newt.flags = 0; 715 newt.flags = 0;
679 setnodevector(L, &newt, nhsize); 716 setnodevector(L, &newt, nhsize);
680 if (newasize < oldasize) { /* will array shrink? */ 717 if (newasize < oldasize) { /* will array shrink? */
681 t->alimit = newasize; /* pretend array has new size... */
682 exchangehashpart(t, &newt); /* and new hash */
683 /* re-insert into the new hash the elements from vanishing slice */ 718 /* re-insert into the new hash the elements from vanishing slice */
684 for (i = newasize; i < oldasize; i++) { 719 exchangehashpart(t, &newt); /* pretend table has new hash */
685 int tag = *getArrTag(t, i); 720 reinsertOldSlice(L, t, oldasize, newasize);
686 if (!tagisempty(tag)) { /* a non-empty entry? */ 721 exchangehashpart(t, &newt); /* restore old hash (in case of errors) */
687 TValue aux;
688 farr2val(t, i + 1, tag, &aux);
689 luaH_setint(L, t, i + 1, &aux);
690 }
691 }
692 t->alimit = oldasize; /* restore current size... */
693 exchangehashpart(t, &newt); /* and hash (in case of errors) */
694 } 722 }
695 /* allocate new array */ 723 /* allocate new array */
696 newarray = resizearray(L, t, oldasize, newasize); 724 newarray = resizearray(L, t, oldasize, newasize);
@@ -702,8 +730,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize,
702 exchangehashpart(t, &newt); /* 't' has the new hash ('newt' has the old) */ 730 exchangehashpart(t, &newt); /* 't' has the new hash ('newt' has the old) */
703 t->array = newarray; /* set new array part */ 731 t->array = newarray; /* set new array part */
704 t->alimit = newasize; 732 t->alimit = newasize;
705 for (i = oldasize; i < newasize; i++) /* clear new slice of the array */ 733 clearNewSlice(t, oldasize, newasize);
706 *getArrTag(t, i) = LUA_VEMPTY;
707 /* re-insert elements from old hash part into new parts */ 734 /* re-insert elements from old hash part into new parts */
708 reinsert(L, &newt, t); /* 'newt' now has the old hash */ 735 reinsert(L, &newt, t); /* 'newt' now has the old hash */
709 freehash(L, &newt); /* free old hash part */ 736 freehash(L, &newt); /* free old hash part */
diff --git a/ltable.h b/ltable.h
index 8b0340b5..8688264c 100644
--- a/ltable.h
+++ b/ltable.h
@@ -87,20 +87,32 @@
87 87
88 88
89/* 89/*
90** The array part of a table is represented by an array of cells. 90** The array part of a table is represented by an array of *cells*.
91** Each cell is composed of NM tags followed by NM values, so that 91** Each cell is composed of NM tags followed by NM values, so that
92** no space is wasted in padding. 92** no space is wasted in padding.
93*/ 93*/
94#define NM cast_uint(sizeof(Value)) 94#define NM cast_uint(sizeof(Value))
95 95
96
97/*
98** A few operations on arrays can be performed "in bulk", treating all
99** tags of a cell as a simple (or a few) word(s). The next constant is
100** the number of words to cover the tags of a cell. (In conventional
101** architectures that will be 1 or 2.)
102*/
103#define BKSZ cast_int((NM - 1) / sizeof(lua_Unsigned) + 1)
104
96struct ArrayCell { 105struct ArrayCell {
97 lu_byte tag[NM]; 106 union {
107 lua_Unsigned bulk[BKSZ]; /* for "bulk" operations */
108 lu_byte tag[NM];
109 } u;
98 Value value[NM]; 110 Value value[NM];
99}; 111};
100 112
101 113
102/* Computes the address of the tag for the abstract index 'k' */ 114/* Computes the address of the tag for the abstract index 'k' */
103#define getArrTag(t,k) (&(t)->array[(k)/NM].tag[(k)%NM]) 115#define getArrTag(t,k) (&(t)->array[(k)/NM].u.tag[(k)%NM])
104 116
105/* Computes the address of the value for the abstract index 'k' */ 117/* Computes the address of the value for the abstract index 'k' */
106#define getArrVal(t,k) (&(t)->array[(k)/NM].value[(k)%NM]) 118#define getArrVal(t,k) (&(t)->array[(k)/NM].value[(k)%NM])