diff options
Diffstat (limited to '')
-rw-r--r-- | lgc.c | 59 | ||||
-rw-r--r-- | ltable.c | 57 | ||||
-rw-r--r-- | ltable.h | 18 |
3 files changed, 99 insertions, 35 deletions
@@ -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 | */ | ||
473 | static 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 | */ | ||
489 | static 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 | */ |
480 | static int traverseephemeron (global_State *g, Table *h, int inv) { | 520 | static 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 | ||
524 | static void traversestrongtable (global_State *g, Table *h) { | 555 | static 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 */ |
@@ -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 | */ | ||
660 | static 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 | */ | ||
681 | static 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 | */ |
669 | void luaH_resize (lua_State *L, Table *t, unsigned int newasize, | 707 | void 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 */ |
@@ -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 | |||
96 | struct ArrayCell { | 105 | struct 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]) |