diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2008-06-26 16:42:45 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2008-06-26 16:42:45 -0300 |
commit | 0c8f5fc2fdcadc8fe6e89c32bf3a1f7456328899 (patch) | |
tree | 3c62e2e59064196eca2fe662196e73e3c45b63cd /lgc.c | |
parent | 1527d8f00d4a99997cf73f50fe159ddba8681f8f (diff) | |
download | lua-0c8f5fc2fdcadc8fe6e89c32bf3a1f7456328899.tar.gz lua-0c8f5fc2fdcadc8fe6e89c32bf3a1f7456328899.tar.bz2 lua-0c8f5fc2fdcadc8fe6e89c32bf3a1f7456328899.zip |
simplification in the handling of finalizers: no more 'tmudata' list +
no more GCSsweeptmu collector's state
Diffstat (limited to 'lgc.c')
-rw-r--r-- | lgc.c | 106 |
1 files changed, 34 insertions, 72 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.45 2008/06/23 16:51:28 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.46 2008/06/23 22:07:44 roberto Exp roberto $ |
3 | ** Garbage Collector | 3 | ** Garbage Collector |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -79,7 +79,7 @@ static void removeentry (Node *n) { | |||
79 | ** The next function tells whether a key or value can be cleared from | 79 | ** The next function tells whether a key or value can be cleared from |
80 | ** a weak table. Non-collectable objects are never removed from weak | 80 | ** a weak table. Non-collectable objects are never removed from weak |
81 | ** tables. Strings behave as `values', so are never removed too. for | 81 | ** tables. Strings behave as `values', so are never removed too. for |
82 | ** other objects: if really collected, cannot keep them; for userdata | 82 | ** other objects: if really collected, cannot keep them; for objects |
83 | ** being finalized, keep them in keys, but not in values | 83 | ** being finalized, keep them in keys, but not in values |
84 | */ | 84 | */ |
85 | static int iscleared (const TValue *o, int iskey) { | 85 | static int iscleared (const TValue *o, int iskey) { |
@@ -205,14 +205,11 @@ static void markmt (global_State *g) { | |||
205 | 205 | ||
206 | 206 | ||
207 | static void markbeingfnz (global_State *g) { | 207 | static void markbeingfnz (global_State *g) { |
208 | GCObject *u = g->tobefnz; | 208 | GCObject *o; |
209 | if (u) { | 209 | for (o = g->tobefnz; o != NULL; o = gch(o)->next) { |
210 | do { | 210 | lua_assert(testbit(gch(o)->marked, SEPARATED)); |
211 | u = gch(u)->next; | 211 | makewhite(g, o); |
212 | lua_assert(testbit(gch(u)->marked, SEPARATED)); | 212 | reallymarkobject(g, o); |
213 | makewhite(g, u); | ||
214 | reallymarkobject(g, u); | ||
215 | } while (u != g->tobefnz); | ||
216 | } | 213 | } |
217 | } | 214 | } |
218 | 215 | ||
@@ -228,7 +225,7 @@ static void markroot (lua_State *L) { | |||
228 | markvalue(g, gt(g->mainthread)); | 225 | markvalue(g, gt(g->mainthread)); |
229 | markvalue(g, registry(L)); | 226 | markvalue(g, registry(L)); |
230 | markmt(g); | 227 | markmt(g); |
231 | markbeingfnz(g); /* mark any finalizing userdata left from previous cycle */ | 228 | markbeingfnz(g); /* mark any finalizing object left from previous cycle */ |
232 | g->gcstate = GCSpropagate; | 229 | g->gcstate = GCSpropagate; |
233 | } | 230 | } |
234 | 231 | ||
@@ -573,17 +570,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { | |||
573 | return p; | 570 | return p; |
574 | } | 571 | } |
575 | 572 | ||
576 | |||
577 | /* sweep list where all objects are alive (dead udata were removed | ||
578 | when separated from this list) */ | ||
579 | static GCObject **unmarklist (global_State *g, GCObject **p, lu_mem count) { | ||
580 | for (; *p != NULL && count-- > 0; p = &gch(*p)->next) { | ||
581 | lua_assert(ttisuserdata(gch(*p)) && !isdead(g, *p)); | ||
582 | makewhite(g, *p); | ||
583 | } | ||
584 | return p; | ||
585 | } | ||
586 | |||
587 | /* }====================================================== */ | 573 | /* }====================================================== */ |
588 | 574 | ||
589 | 575 | ||
@@ -602,18 +588,14 @@ static void checkSizes (lua_State *L) { | |||
602 | 588 | ||
603 | 589 | ||
604 | static Udata *udata2finalize (global_State *g) { | 590 | static Udata *udata2finalize (global_State *g) { |
605 | GCObject *o = gch(g->tobefnz)->next; /* get first element */ | 591 | GCObject *o = g->tobefnz; /* get first element */ |
606 | Udata *udata = rawgco2u(o); | 592 | g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */ |
607 | /* remove udata from `tobefnz' */ | 593 | gch(o)->next = g->rootgc; /* return it to `root' list */ |
608 | if (o == g->tobefnz) /* last element? */ | 594 | g->rootgc = o; |
609 | g->tobefnz = NULL; | 595 | lua_assert(isfinalized(gch(o))); |
610 | else | 596 | resetbit(gch(o)->marked, SEPARATED); /* mark it as such */ |
611 | gch(g->tobefnz)->next = udata->uv.next; | ||
612 | udata->uv.next = g->mainthread->next; /* return it to `root' list */ | ||
613 | g->mainthread->next = o; | ||
614 | resetbit(udata->uv.marked, SEPARATED); /* mark it as such */ | ||
615 | makewhite(g, o); | 597 | makewhite(g, o); |
616 | return udata; | 598 | return rawgco2u(o); |
617 | } | 599 | } |
618 | 600 | ||
619 | 601 | ||
@@ -639,28 +621,21 @@ static void GCTM (lua_State *L) { | |||
639 | /* | 621 | /* |
640 | ** Call all GC tag methods | 622 | ** Call all GC tag methods |
641 | */ | 623 | */ |
642 | void luaC_callGCTM (lua_State *L) { | 624 | void luaC_callAllGCTM (lua_State *L) { |
643 | global_State *g = G(L); | 625 | while (G(L)->tobefnz) GCTM(L); |
644 | GCObject *last = g->tobefnz; | ||
645 | GCObject *curr; | ||
646 | if (last == NULL) return; /* empty list? */ | ||
647 | do { | ||
648 | curr = gch(g->tobefnz)->next; /* element to be collected */ | ||
649 | GCTM(L); | ||
650 | } while (curr != last); /* go only until original last */ | ||
651 | /* do not finalize new udata created during previous finalizations */ | ||
652 | while (g->tobefnz) | ||
653 | udata2finalize(g); /* simply remove them from list */ | ||
654 | } | 626 | } |
655 | 627 | ||
656 | 628 | ||
657 | /* move 'dead' udata that need finalization to list 'tobefnz' */ | 629 | /* move 'dead' udata that need finalization to list 'tobefnz' */ |
658 | size_t luaC_separateudata (lua_State *L, int all) { | 630 | size_t luaC_separateudata (lua_State *L, int all) { |
659 | global_State *g = G(L); | 631 | global_State *g = G(L); |
660 | size_t deadmem = 0; | 632 | size_t deadmem = 0; /* total size of all objects to be finalized */ |
661 | GCObject **p = &g->tmudata; | 633 | GCObject **p = &g->mainthread->next; |
662 | GCObject *curr; | 634 | GCObject *curr; |
663 | while ((curr = *p) != NULL) { | 635 | GCObject **lastnext = &g->tobefnz; |
636 | /* find last 'next' field in 'tobefnz' list (to insert elements in its end) */ | ||
637 | while (*lastnext != NULL) lastnext = &gch(*lastnext)->next; | ||
638 | while ((curr = *p) != NULL) { /* traverse all finalizable objects */ | ||
664 | lua_assert(ttisuserdata(gch(curr)) && !isfinalized(gco2u(curr))); | 639 | lua_assert(ttisuserdata(gch(curr)) && !isfinalized(gco2u(curr))); |
665 | lua_assert(testbit(gch(curr)->marked, SEPARATED)); | 640 | lua_assert(testbit(gch(curr)->marked, SEPARATED)); |
666 | if (!(all || iswhite(curr))) /* not being collected? */ | 641 | if (!(all || iswhite(curr))) /* not being collected? */ |
@@ -668,15 +643,11 @@ size_t luaC_separateudata (lua_State *L, int all) { | |||
668 | else { | 643 | else { |
669 | l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ | 644 | l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ |
670 | deadmem += sizeudata(gco2u(curr)); | 645 | deadmem += sizeudata(gco2u(curr)); |
671 | *p = gch(curr)->next; /* remove 'curr' from 'tmudata' list */ | 646 | *p = gch(curr)->next; /* remove 'curr' from 'rootgc' list */ |
672 | /* link 'curr' at the end of 'tobefnz' list */ | 647 | /* link 'curr' at the end of 'tobefnz' list */ |
673 | if (g->tobefnz == NULL) /* list is empty? */ | 648 | gch(curr)->next = *lastnext; |
674 | g->tobefnz = gch(curr)->next = curr; /* creates a circular list */ | 649 | *lastnext = curr; |
675 | else { | 650 | lastnext = &gch(curr)->next; |
676 | gch(curr)->next = gch(g->tobefnz)->next; | ||
677 | gch(g->tobefnz)->next = curr; | ||
678 | g->tobefnz = curr; | ||
679 | } | ||
680 | } | 651 | } |
681 | } | 652 | } |
682 | return deadmem; | 653 | return deadmem; |
@@ -689,13 +660,13 @@ void luaC_checkfinalizer (lua_State *L, Udata *u) { | |||
689 | isfinalized(&u->uv) || /* ... or is finalized... */ | 660 | isfinalized(&u->uv) || /* ... or is finalized... */ |
690 | gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */ | 661 | gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */ |
691 | return; /* nothing to be done */ | 662 | return; /* nothing to be done */ |
692 | else { /* move 'u' from root list to 'tmudata' list */ | 663 | else { /* move 'u' to 2nd part of root list */ |
693 | GCObject **p; | 664 | GCObject **p; |
694 | for (p = &g->rootgc; *p != obj2gco(u); p = &gch(*p)->next) | 665 | for (p = &g->rootgc; *p != obj2gco(u); p = &gch(*p)->next) |
695 | lua_assert(*p != NULL); /* 'u' must be in this list */ | 666 | lua_assert(*p != obj2gco(g->mainthread)); /* 'u' must be in this list */ |
696 | *p = u->uv.next; /* remove 'u' from root list */ | 667 | *p = u->uv.next; /* remove 'u' from root list */ |
697 | u->uv.next = g->tmudata; /* link it in 'tmudata' list */ | 668 | u->uv.next = g->mainthread->next; /* re-link it in list */ |
698 | g->tmudata = obj2gco(u); | 669 | g->mainthread->next = obj2gco(u); |
699 | l_setbit(u->uv.marked, SEPARATED); /* mark it as such */ | 670 | l_setbit(u->uv.marked, SEPARATED); /* mark it as such */ |
700 | } | 671 | } |
701 | } | 672 | } |
@@ -716,9 +687,8 @@ void luaC_freeall (lua_State *L) { | |||
716 | /* mask to collect all elements */ | 687 | /* mask to collect all elements */ |
717 | g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); | 688 | g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); |
718 | sweepwholelist(L, &g->rootgc); | 689 | sweepwholelist(L, &g->rootgc); |
719 | lua_assert(g->rootgc == obj2gco(L)); | 690 | lua_assert(g->rootgc == obj2gco(g->mainthread)); |
720 | sweepwholelist(L, &g->tmudata); | 691 | lua_assert(g->mainthread->next == NULL); |
721 | lua_assert(g->tmudata == NULL); | ||
722 | for (i = 0; i < g->strt.size; i++) /* free all string lists */ | 692 | for (i = 0; i < g->strt.size; i++) /* free all string lists */ |
723 | sweepwholelist(L, &g->strt.hash[i]); | 693 | sweepwholelist(L, &g->strt.hash[i]); |
724 | lua_assert(g->strt.nuse == 0); | 694 | lua_assert(g->strt.nuse == 0); |
@@ -781,18 +751,10 @@ static l_mem singlestep (lua_State *L) { | |||
781 | case GCSsweepstring: { | 751 | case GCSsweepstring: { |
782 | correctestimate(g, sweepwholelist(L, &g->strt.hash[g->sweepstrgc++])); | 752 | correctestimate(g, sweepwholelist(L, &g->strt.hash[g->sweepstrgc++])); |
783 | if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */ | 753 | if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */ |
784 | g->sweepgc = &g->tmudata; | ||
785 | g->gcstate = GCSsweeptmu; /* end sweep-string phase */ | ||
786 | } | ||
787 | return GCSWEEPCOST; | ||
788 | } | ||
789 | case GCSsweeptmu: { | ||
790 | g->sweepgc = unmarklist(g, g->sweepgc, GCSWEEPMAX); | ||
791 | if (*g->sweepgc == NULL) { /* nothing more to sweep? */ | ||
792 | g->sweepgc = &g->rootgc; | 754 | g->sweepgc = &g->rootgc; |
793 | g->gcstate = GCSsweep; /* sweep all other objects */ | 755 | g->gcstate = GCSsweep; /* sweep all other objects */ |
794 | } | 756 | } |
795 | return GCSWEEPMAX*GCSWEEPCOST; | 757 | return GCSWEEPCOST; |
796 | } | 758 | } |
797 | case GCSsweep: { | 759 | case GCSsweep: { |
798 | correctestimate(g, g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX)); | 760 | correctestimate(g, g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX)); |