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)); |
