diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2008-06-23 13:51:28 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2008-06-23 13:51:28 -0300 |
| commit | 7ba62e29856458469ae42a7be83856a0ec81e539 (patch) | |
| tree | 797003f8157d2b17137c6d73028884e4add10cc6 | |
| parent | 8fd28611d5438b913dc7536d175df106727e2584 (diff) | |
| download | lua-7ba62e29856458469ae42a7be83856a0ec81e539.tar.gz lua-7ba62e29856458469ae42a7be83856a0ec81e539.tar.bz2 lua-7ba62e29856458469ae42a7be83856a0ec81e539.zip | |
code reorganization (only changed comments and order of functions)
| -rw-r--r-- | lgc.c | 357 |
1 files changed, 203 insertions, 154 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.c,v 2.43 2008/02/11 15:46:03 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.44 2008/02/19 18:55:09 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 | */ |
| @@ -53,6 +53,15 @@ | |||
| 53 | #define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause) | 53 | #define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause) |
| 54 | 54 | ||
| 55 | 55 | ||
| 56 | static void reallymarkobject (global_State *g, GCObject *o); | ||
| 57 | |||
| 58 | |||
| 59 | /* | ||
| 60 | ** {====================================================== | ||
| 61 | ** Generic functions | ||
| 62 | ** ======================================================= | ||
| 63 | */ | ||
| 64 | |||
| 56 | static void linktable (Table *h, GCObject **p) { | 65 | static void linktable (Table *h, GCObject **p) { |
| 57 | h->gclist = *p; | 66 | h->gclist = *p; |
| 58 | *p = obj2gco(h); | 67 | *p = obj2gco(h); |
| @@ -83,6 +92,65 @@ static int iscleared (const TValue *o, int iskey) { | |||
| 83 | (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); | 92 | (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); |
| 84 | } | 93 | } |
| 85 | 94 | ||
| 95 | void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { | ||
| 96 | global_State *g = G(L); | ||
| 97 | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); | ||
| 98 | lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); | ||
| 99 | lua_assert(ttype(gch(o)) != LUA_TTABLE); | ||
| 100 | /* must keep invariant? */ | ||
| 101 | if (g->gcstate == GCSpropagate) | ||
| 102 | reallymarkobject(g, v); /* restore invariant */ | ||
| 103 | else /* don't mind */ | ||
| 104 | makewhite(g, o); /* mark as white just to avoid other barriers */ | ||
| 105 | } | ||
| 106 | |||
| 107 | |||
| 108 | void luaC_barrierback (lua_State *L, Table *t) { | ||
| 109 | global_State *g = G(L); | ||
| 110 | GCObject *o = obj2gco(t); | ||
| 111 | lua_assert(isblack(o) && !isdead(g, o)); | ||
| 112 | lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); | ||
| 113 | black2gray(o); /* make table gray (again) */ | ||
| 114 | t->gclist = g->grayagain; | ||
| 115 | g->grayagain = o; | ||
| 116 | } | ||
| 117 | |||
| 118 | |||
| 119 | void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { | ||
| 120 | global_State *g = G(L); | ||
| 121 | gch(o)->marked = luaC_white(g); | ||
| 122 | gch(o)->tt = tt; | ||
| 123 | gch(o)->next = g->rootgc; | ||
| 124 | g->rootgc = o; | ||
| 125 | } | ||
| 126 | |||
| 127 | |||
| 128 | void luaC_linkupval (lua_State *L, UpVal *uv) { | ||
| 129 | global_State *g = G(L); | ||
| 130 | GCObject *o = obj2gco(uv); | ||
| 131 | gch(o)->next = g->rootgc; /* link upvalue into `rootgc' list */ | ||
| 132 | g->rootgc = o; | ||
| 133 | if (isgray(o)) { | ||
| 134 | if (g->gcstate == GCSpropagate) { | ||
| 135 | gray2black(o); /* closed upvalues need barrier */ | ||
| 136 | luaC_barrier(L, uv, uv->v); | ||
| 137 | } | ||
| 138 | else { /* sweep phase: sweep it (turning it into white) */ | ||
| 139 | makewhite(g, o); | ||
| 140 | lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); | ||
| 141 | } | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | /* }====================================================== */ | ||
| 146 | |||
| 147 | |||
| 148 | |||
| 149 | /* | ||
| 150 | ** {====================================================== | ||
| 151 | ** Mark functions | ||
| 152 | ** ======================================================= | ||
| 153 | */ | ||
| 86 | 154 | ||
| 87 | static void reallymarkobject (global_State *g, GCObject *o) { | 155 | static void reallymarkobject (global_State *g, GCObject *o) { |
| 88 | lua_assert(iswhite(o) && !isdead(g, o)); | 156 | lua_assert(iswhite(o) && !isdead(g, o)); |
| @@ -129,36 +197,60 @@ static void reallymarkobject (global_State *g, GCObject *o) { | |||
| 129 | } | 197 | } |
| 130 | 198 | ||
| 131 | 199 | ||
| 132 | /* move 'dead' udata that need finalization to list 'tobefnz' */ | 200 | static void markmt (global_State *g) { |
| 133 | size_t luaC_separateudata (lua_State *L, int all) { | 201 | int i; |
| 202 | for (i=0; i<NUM_TAGS; i++) | ||
| 203 | markobject(g, g->mt[i]); | ||
| 204 | } | ||
| 205 | |||
| 206 | |||
| 207 | static void markbeingfnz (global_State *g) { | ||
| 208 | GCObject *u = g->tobefnz; | ||
| 209 | if (u) { | ||
| 210 | do { | ||
| 211 | u = gch(u)->next; | ||
| 212 | lua_assert(testbit(gch(u)->marked, SEPARATED)); | ||
| 213 | lua_assert(!iswhite(u)); /* must be marked, if left from previous GC */ | ||
| 214 | makewhite(g, u); | ||
| 215 | reallymarkobject(g, u); | ||
| 216 | } while (u != g->tobefnz); | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | |||
| 221 | /* mark root set */ | ||
| 222 | static void markroot (lua_State *L) { | ||
| 134 | global_State *g = G(L); | 223 | global_State *g = G(L); |
| 135 | size_t deadmem = 0; | 224 | g->gray = NULL; |
| 136 | GCObject **p = &g->tmudata; | 225 | g->grayagain = NULL; |
| 137 | GCObject *curr; | 226 | g->weak = g->ephemeron = g->allweak = NULL; |
| 138 | while ((curr = *p) != NULL) { | 227 | markobject(g, g->mainthread); |
| 139 | lua_assert(ttisuserdata(gch(curr)) && !isfinalized(gco2u(curr))); | 228 | /* make global table be traversed before main stack */ |
| 140 | lua_assert(testbit(gch(curr)->marked, SEPARATED)); | 229 | markvalue(g, gt(g->mainthread)); |
| 141 | if (all) makewhite(g, curr); /* if 'all', collect all objects */ | 230 | markvalue(g, registry(L)); |
| 142 | if (!iswhite(curr)) /* not being collected? */ | 231 | markmt(g); |
| 143 | p = &gch(curr)->next; /* don't bother with it */ | 232 | markbeingfnz(g); /* mark any finalizing userdata left from previous cycle */ |
| 144 | else { | 233 | g->gcstate = GCSpropagate; |
| 145 | l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ | 234 | } |
| 146 | reallymarkobject(g, curr); /* won't be collected now */ | 235 | |
| 147 | deadmem += sizeudata(gco2u(curr)); | 236 | |
| 148 | *p = gch(curr)->next; /* remove 'curr' from 'tmudata' list */ | 237 | static void remarkupvals (global_State *g) { |
| 149 | /* link 'curr' at the end of 'tobefnz' list */ | 238 | UpVal *uv; |
| 150 | if (g->tobefnz == NULL) /* list is empty? */ | 239 | for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { |
| 151 | g->tobefnz = gch(curr)->next = curr; /* creates a circular list */ | 240 | lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); |
| 152 | else { | 241 | if (isgray(obj2gco(uv))) |
| 153 | gch(curr)->next = gch(g->tobefnz)->next; | 242 | markvalue(g, uv->v); |
| 154 | gch(g->tobefnz)->next = curr; | ||
| 155 | g->tobefnz = curr; | ||
| 156 | } | ||
| 157 | } | ||
| 158 | } | 243 | } |
| 159 | return deadmem; | ||
| 160 | } | 244 | } |
| 161 | 245 | ||
| 246 | /* }====================================================== */ | ||
| 247 | |||
| 248 | |||
| 249 | /* | ||
| 250 | ** {====================================================== | ||
| 251 | ** Traverse functions | ||
| 252 | ** ======================================================= | ||
| 253 | */ | ||
| 162 | 254 | ||
| 163 | static void traverseweakvalue (global_State *g, Table *h) { | 255 | static void traverseweakvalue (global_State *g, Table *h) { |
| 164 | int i = sizenode(h); | 256 | int i = sizenode(h); |
| @@ -382,6 +474,14 @@ static size_t propagateall (global_State *g) { | |||
| 382 | } | 474 | } |
| 383 | 475 | ||
| 384 | 476 | ||
| 477 | static void traverselistofgrays (global_State *g, GCObject **l) { | ||
| 478 | lua_assert(g->gray == NULL); /* no grays left */ | ||
| 479 | g->gray = *l; /* now 'l' is new gray list */ | ||
| 480 | *l = NULL; | ||
| 481 | propagateall(g); | ||
| 482 | } | ||
| 483 | |||
| 484 | |||
| 385 | static void convergeephemerons (global_State *g) { | 485 | static void convergeephemerons (global_State *g) { |
| 386 | int changed; | 486 | int changed; |
| 387 | do { | 487 | do { |
| @@ -399,11 +499,16 @@ static void convergeephemerons (global_State *g) { | |||
| 399 | } while (changed); | 499 | } while (changed); |
| 400 | } | 500 | } |
| 401 | 501 | ||
| 502 | /* }====================================================== */ | ||
| 402 | 503 | ||
| 403 | 504 | ||
| 404 | /* | 505 | /* |
| 405 | ** clear collected entries from weaktables | 506 | ** {====================================================== |
| 507 | ** Sweep Functions | ||
| 508 | ** ======================================================= | ||
| 406 | */ | 509 | */ |
| 510 | |||
| 511 | /* clear collected entries from weaktables */ | ||
| 407 | static void cleartable (GCObject *l) { | 512 | static void cleartable (GCObject *l) { |
| 408 | while (l) { | 513 | while (l) { |
| 409 | Table *h = gco2t(l); | 514 | Table *h = gco2t(l); |
| @@ -445,7 +550,6 @@ static void freeobj (lua_State *L, GCObject *o) { | |||
| 445 | } | 550 | } |
| 446 | 551 | ||
| 447 | 552 | ||
| 448 | |||
| 449 | #define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) | 553 | #define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) |
| 450 | 554 | ||
| 451 | 555 | ||
| @@ -471,6 +575,8 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { | |||
| 471 | } | 575 | } |
| 472 | 576 | ||
| 473 | 577 | ||
| 578 | /* sweep list where all objects are alive (dead udata were removed | ||
| 579 | when separated from this list) */ | ||
| 474 | static GCObject **unmarklist (global_State *g, GCObject **p, lu_mem count) { | 580 | static GCObject **unmarklist (global_State *g, GCObject **p, lu_mem count) { |
| 475 | for (; *p != NULL && count-- > 0; p = &gch(*p)->next) { | 581 | for (; *p != NULL && count-- > 0; p = &gch(*p)->next) { |
| 476 | lua_assert(ttisuserdata(gch(*p)) && !isdead(g, *p)); | 582 | lua_assert(ttisuserdata(gch(*p)) && !isdead(g, *p)); |
| @@ -479,6 +585,14 @@ static GCObject **unmarklist (global_State *g, GCObject **p, lu_mem count) { | |||
| 479 | return p; | 585 | return p; |
| 480 | } | 586 | } |
| 481 | 587 | ||
| 588 | /* }====================================================== */ | ||
| 589 | |||
| 590 | |||
| 591 | /* | ||
| 592 | ** {====================================================== | ||
| 593 | ** Finalization | ||
| 594 | ** ======================================================= | ||
| 595 | */ | ||
| 482 | 596 | ||
| 483 | static void checkSizes (lua_State *L) { | 597 | static void checkSizes (lua_State *L) { |
| 484 | global_State *g = G(L); | 598 | global_State *g = G(L); |
| @@ -541,6 +655,63 @@ void luaC_callGCTM (lua_State *L) { | |||
| 541 | } | 655 | } |
| 542 | 656 | ||
| 543 | 657 | ||
| 658 | /* move 'dead' udata that need finalization to list 'tobefnz' */ | ||
| 659 | size_t luaC_separateudata (lua_State *L, int all) { | ||
| 660 | global_State *g = G(L); | ||
| 661 | size_t deadmem = 0; | ||
| 662 | GCObject **p = &g->tmudata; | ||
| 663 | GCObject *curr; | ||
| 664 | while ((curr = *p) != NULL) { | ||
| 665 | lua_assert(ttisuserdata(gch(curr)) && !isfinalized(gco2u(curr))); | ||
| 666 | lua_assert(testbit(gch(curr)->marked, SEPARATED)); | ||
| 667 | if (all) makewhite(g, curr); /* if 'all', collect all objects */ | ||
| 668 | if (!iswhite(curr)) /* not being collected? */ | ||
| 669 | p = &gch(curr)->next; /* don't bother with it */ | ||
| 670 | else { | ||
| 671 | l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ | ||
| 672 | reallymarkobject(g, curr); /* won't be collected now */ | ||
| 673 | deadmem += sizeudata(gco2u(curr)); | ||
| 674 | *p = gch(curr)->next; /* remove 'curr' from 'tmudata' list */ | ||
| 675 | /* link 'curr' at the end of 'tobefnz' list */ | ||
| 676 | if (g->tobefnz == NULL) /* list is empty? */ | ||
| 677 | g->tobefnz = gch(curr)->next = curr; /* creates a circular list */ | ||
| 678 | else { | ||
| 679 | gch(curr)->next = gch(g->tobefnz)->next; | ||
| 680 | gch(g->tobefnz)->next = curr; | ||
| 681 | g->tobefnz = curr; | ||
| 682 | } | ||
| 683 | } | ||
| 684 | } | ||
| 685 | return deadmem; | ||
| 686 | } | ||
| 687 | |||
| 688 | |||
| 689 | void luaC_checkfinalizer (lua_State *L, Udata *u) { | ||
| 690 | global_State *g = G(L); | ||
| 691 | if (testbit(u->uv.marked, SEPARATED) || /* userdata is already separated... */ | ||
| 692 | isfinalized(&u->uv) || /* ... or is finalized... */ | ||
| 693 | gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */ | ||
| 694 | return; /* nothing to be done */ | ||
| 695 | else { /* move 'u' from root list to 'tmudata' list */ | ||
| 696 | GCObject **p; | ||
| 697 | for (p = &g->rootgc; *p != obj2gco(u); p = &gch(*p)->next) | ||
| 698 | lua_assert(*p != NULL); /* 'u' must be in this list */ | ||
| 699 | *p = u->uv.next; /* remove 'u' from root list */ | ||
| 700 | u->uv.next = g->tmudata; /* link it in 'tmudata' list */ | ||
| 701 | g->tmudata = obj2gco(u); | ||
| 702 | l_setbit(u->uv.marked, SEPARATED); /* mark it as such */ | ||
| 703 | } | ||
| 704 | } | ||
| 705 | |||
| 706 | /* }====================================================== */ | ||
| 707 | |||
| 708 | |||
| 709 | /* | ||
| 710 | ** {====================================================== | ||
| 711 | ** GC control | ||
| 712 | ** ======================================================= | ||
| 713 | */ | ||
| 714 | |||
| 544 | void luaC_freeall (lua_State *L) { | 715 | void luaC_freeall (lua_State *L) { |
| 545 | global_State *g = G(L); | 716 | global_State *g = G(L); |
| 546 | int i; | 717 | int i; |
| @@ -557,61 +728,6 @@ void luaC_freeall (lua_State *L) { | |||
| 557 | } | 728 | } |
| 558 | 729 | ||
| 559 | 730 | ||
| 560 | static void markmt (global_State *g) { | ||
| 561 | int i; | ||
| 562 | for (i=0; i<NUM_TAGS; i++) | ||
| 563 | markobject(g, g->mt[i]); | ||
| 564 | } | ||
| 565 | |||
| 566 | |||
| 567 | static void markbeingfnz (global_State *g) { | ||
| 568 | GCObject *u = g->tobefnz; | ||
| 569 | if (u) { | ||
| 570 | do { | ||
| 571 | u = gch(u)->next; | ||
| 572 | lua_assert(testbit(gch(u)->marked, SEPARATED)); | ||
| 573 | lua_assert(!iswhite(u)); /* must be marked, if left from previous GC */ | ||
| 574 | makewhite(g, u); | ||
| 575 | reallymarkobject(g, u); | ||
| 576 | } while (u != g->tobefnz); | ||
| 577 | } | ||
| 578 | } | ||
| 579 | |||
| 580 | |||
| 581 | /* mark root set */ | ||
| 582 | static void markroot (lua_State *L) { | ||
| 583 | global_State *g = G(L); | ||
| 584 | g->gray = NULL; | ||
| 585 | g->grayagain = NULL; | ||
| 586 | g->weak = g->ephemeron = g->allweak = NULL; | ||
| 587 | markobject(g, g->mainthread); | ||
| 588 | /* make global table be traversed before main stack */ | ||
| 589 | markvalue(g, gt(g->mainthread)); | ||
| 590 | markvalue(g, registry(L)); | ||
| 591 | markmt(g); | ||
| 592 | markbeingfnz(g); /* mark any finalizing userdata left from previous cycle */ | ||
| 593 | g->gcstate = GCSpropagate; | ||
| 594 | } | ||
| 595 | |||
| 596 | |||
| 597 | static void remarkupvals (global_State *g) { | ||
| 598 | UpVal *uv; | ||
| 599 | for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { | ||
| 600 | lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); | ||
| 601 | if (isgray(obj2gco(uv))) | ||
| 602 | markvalue(g, uv->v); | ||
| 603 | } | ||
| 604 | } | ||
| 605 | |||
| 606 | |||
| 607 | static void marklistofgrays (global_State *g, GCObject **l) { | ||
| 608 | lua_assert(g->gray == NULL); /* no grays left */ | ||
| 609 | g->gray = *l; /* now 'l' is new gray list */ | ||
| 610 | *l = NULL; | ||
| 611 | propagateall(g); | ||
| 612 | } | ||
| 613 | |||
| 614 | |||
| 615 | static void atomic (lua_State *L) { | 731 | static void atomic (lua_State *L) { |
| 616 | global_State *g = G(L); | 732 | global_State *g = G(L); |
| 617 | size_t udsize; /* total size of userdata to be finalized */ | 733 | size_t udsize; /* total size of userdata to be finalized */ |
| @@ -626,8 +742,8 @@ static void atomic (lua_State *L) { | |||
| 626 | markobject(g, L); /* mark running thread */ | 742 | markobject(g, L); /* mark running thread */ |
| 627 | markmt(g); /* mark basic metatables (again) */ | 743 | markmt(g); /* mark basic metatables (again) */ |
| 628 | propagateall(g); | 744 | propagateall(g); |
| 629 | marklistofgrays(g, &g->ephemeron); /* remark ephemeron tables */ | 745 | traverselistofgrays(g, &g->ephemeron); /* remark ephemeron tables */ |
| 630 | marklistofgrays(g, &g->grayagain); /* remark gray again */ | 746 | traverselistofgrays(g, &g->grayagain); /* remark gray again */ |
| 631 | convergeephemerons(g); | 747 | convergeephemerons(g); |
| 632 | udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ | 748 | udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ |
| 633 | udsize += propagateall(g); /* remark, to propagate `preserveness' */ | 749 | udsize += propagateall(g); /* remark, to propagate `preserveness' */ |
| @@ -762,73 +878,6 @@ void luaC_fullgc (lua_State *L, int isemergency) { | |||
| 762 | setthreshold(g); | 878 | setthreshold(g); |
| 763 | } | 879 | } |
| 764 | 880 | ||
| 765 | 881 | /* }====================================================== */ | |
| 766 | void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { | ||
| 767 | global_State *g = G(L); | ||
| 768 | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); | ||
| 769 | lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); | ||
| 770 | lua_assert(ttype(gch(o)) != LUA_TTABLE); | ||
| 771 | /* must keep invariant? */ | ||
| 772 | if (g->gcstate == GCSpropagate) | ||
| 773 | reallymarkobject(g, v); /* restore invariant */ | ||
| 774 | else /* don't mind */ | ||
| 775 | makewhite(g, o); /* mark as white just to avoid other barriers */ | ||
| 776 | } | ||
| 777 | |||
| 778 | |||
| 779 | void luaC_barrierback (lua_State *L, Table *t) { | ||
| 780 | global_State *g = G(L); | ||
| 781 | GCObject *o = obj2gco(t); | ||
| 782 | lua_assert(isblack(o) && !isdead(g, o)); | ||
| 783 | lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); | ||
| 784 | black2gray(o); /* make table gray (again) */ | ||
| 785 | t->gclist = g->grayagain; | ||
| 786 | g->grayagain = o; | ||
| 787 | } | ||
| 788 | |||
| 789 | |||
| 790 | void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { | ||
| 791 | global_State *g = G(L); | ||
| 792 | gch(o)->marked = luaC_white(g); | ||
| 793 | gch(o)->tt = tt; | ||
| 794 | gch(o)->next = g->rootgc; | ||
| 795 | g->rootgc = o; | ||
| 796 | } | ||
| 797 | |||
| 798 | |||
| 799 | void luaC_linkupval (lua_State *L, UpVal *uv) { | ||
| 800 | global_State *g = G(L); | ||
| 801 | GCObject *o = obj2gco(uv); | ||
| 802 | gch(o)->next = g->rootgc; /* link upvalue into `rootgc' list */ | ||
| 803 | g->rootgc = o; | ||
| 804 | if (isgray(o)) { | ||
| 805 | if (g->gcstate == GCSpropagate) { | ||
| 806 | gray2black(o); /* closed upvalues need barrier */ | ||
| 807 | luaC_barrier(L, uv, uv->v); | ||
| 808 | } | ||
| 809 | else { /* sweep phase: sweep it (turning it into white) */ | ||
| 810 | makewhite(g, o); | ||
| 811 | lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); | ||
| 812 | } | ||
| 813 | } | ||
| 814 | } | ||
| 815 | |||
| 816 | |||
| 817 | void luaC_checkfinalizer (lua_State *L, Udata *u) { | ||
| 818 | global_State *g = G(L); | ||
| 819 | if (testbit(u->uv.marked, SEPARATED) || /* userdata is already separated... */ | ||
| 820 | isfinalized(&u->uv) || /* ... or is finalized... */ | ||
| 821 | gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */ | ||
| 822 | return; /* nothing to be done */ | ||
| 823 | else { /* move 'u' from root list to tobefnz list */ | ||
| 824 | GCObject **p; | ||
| 825 | for (p = &g->rootgc; *p != obj2gco(u); p = &gch(*p)->next) | ||
| 826 | lua_assert(*p != NULL); /* 'u' must be in this list */ | ||
| 827 | *p = u->uv.next; /* remove 'u' from root list */ | ||
| 828 | u->uv.next = g->tmudata; /* link it in tobefnz list */ | ||
| 829 | g->tmudata = obj2gco(u); | ||
| 830 | l_setbit(u->uv.marked, SEPARATED); /* mark it as such */ | ||
| 831 | } | ||
| 832 | } | ||
| 833 | 882 | ||
| 834 | 883 | ||
