diff options
Diffstat (limited to 'lgc.c')
| -rw-r--r-- | lgc.c | 237 |
1 files changed, 135 insertions, 102 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.c,v 2.42 2007/10/31 15:41:19 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.43 2008/02/11 15:46:03 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 | */ |
| @@ -29,24 +29,22 @@ | |||
| 29 | #define GCFINALIZECOST 100 | 29 | #define GCFINALIZECOST 100 |
| 30 | 30 | ||
| 31 | 31 | ||
| 32 | #define maskmarks cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) | 32 | #define maskcolors cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) |
| 33 | 33 | ||
| 34 | #define makewhite(g,x) \ | 34 | #define makewhite(g,x) \ |
| 35 | ((x)->gch.marked = cast_byte(((x)->gch.marked & maskmarks) | luaC_white(g))) | 35 | (gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | luaC_white(g))) |
| 36 | 36 | ||
| 37 | #define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) | 37 | #define white2gray(x) resetbits(gch(x)->marked, WHITEBITS) |
| 38 | #define black2gray(x) resetbit((x)->gch.marked, BLACKBIT) | 38 | #define black2gray(x) resetbit(gch(x)->marked, BLACKBIT) |
| 39 | 39 | ||
| 40 | #define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) | 40 | #define stringmark(s) resetbits((s)->tsv.marked, WHITEBITS) |
| 41 | 41 | ||
| 42 | 42 | ||
| 43 | #define isfinalized(u) testbit((u)->marked, FINALIZEDBIT) | 43 | #define isfinalized(u) testbit((u)->marked, FINALIZEDBIT) |
| 44 | #define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT) | ||
| 45 | |||
| 46 | 44 | ||
| 47 | 45 | ||
| 48 | #define markvalue(g,o) { checkconsistency(o); \ | 46 | #define markvalue(g,o) { checkconsistency(o); \ |
| 49 | if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } | 47 | if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } |
| 50 | 48 | ||
| 51 | #define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \ | 49 | #define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \ |
| 52 | reallymarkobject(g, obj2gco(t)); } | 50 | reallymarkobject(g, obj2gco(t)); } |
| @@ -89,7 +87,7 @@ static int iscleared (const TValue *o, int iskey) { | |||
| 89 | static void reallymarkobject (global_State *g, GCObject *o) { | 87 | static void reallymarkobject (global_State *g, GCObject *o) { |
| 90 | lua_assert(iswhite(o) && !isdead(g, o)); | 88 | lua_assert(iswhite(o) && !isdead(g, o)); |
| 91 | white2gray(o); | 89 | white2gray(o); |
| 92 | switch (o->gch.tt) { | 90 | switch (gch(o)->tt) { |
| 93 | case LUA_TSTRING: { | 91 | case LUA_TSTRING: { |
| 94 | return; | 92 | return; |
| 95 | } | 93 | } |
| @@ -113,7 +111,7 @@ static void reallymarkobject (global_State *g, GCObject *o) { | |||
| 113 | break; | 111 | break; |
| 114 | } | 112 | } |
| 115 | case LUA_TTABLE: { | 113 | case LUA_TTABLE: { |
| 116 | linktable(gco2h(o), &g->gray); | 114 | linktable(gco2t(o), &g->gray); |
| 117 | break; | 115 | break; |
| 118 | } | 116 | } |
| 119 | case LUA_TTHREAD: { | 117 | case LUA_TTHREAD: { |
| @@ -131,42 +129,30 @@ static void reallymarkobject (global_State *g, GCObject *o) { | |||
| 131 | } | 129 | } |
| 132 | 130 | ||
| 133 | 131 | ||
| 134 | static void marktmu (global_State *g) { | 132 | /* move 'dead' udata that need finalization to list 'tobefnz' */ |
| 135 | GCObject *u = g->tmudata; | ||
| 136 | if (u) { | ||
| 137 | do { | ||
| 138 | u = u->gch.next; | ||
| 139 | makewhite(g, u); /* may be marked, if left from previous GC */ | ||
| 140 | reallymarkobject(g, u); | ||
| 141 | } while (u != g->tmudata); | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | |||
| 146 | /* move `dead' udata that need finalization to list `tmudata' */ | ||
| 147 | size_t luaC_separateudata (lua_State *L, int all) { | 133 | size_t luaC_separateudata (lua_State *L, int all) { |
| 148 | global_State *g = G(L); | 134 | global_State *g = G(L); |
| 149 | size_t deadmem = 0; | 135 | size_t deadmem = 0; |
| 150 | GCObject **p = &g->mainthread->next; | 136 | GCObject **p = &g->tmudata; |
| 151 | GCObject *curr; | 137 | GCObject *curr; |
| 152 | while ((curr = *p) != NULL) { | 138 | while ((curr = *p) != NULL) { |
| 153 | if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) | 139 | lua_assert(ttisuserdata(gch(curr)) && !isfinalized(gco2u(curr))); |
| 154 | p = &curr->gch.next; /* don't bother with them */ | 140 | lua_assert(testbit(gch(curr)->marked, SEPARATED)); |
| 155 | else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { | 141 | if (all) makewhite(g, curr); /* if 'all', collect all objects */ |
| 156 | markfinalized(gco2u(curr)); /* don't need finalization */ | 142 | if (!iswhite(curr)) /* not being collected? */ |
| 157 | p = &curr->gch.next; | 143 | p = &gch(curr)->next; /* don't bother with it */ |
| 158 | } | 144 | else { |
| 159 | else { /* must call its gc method */ | 145 | l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ |
| 146 | reallymarkobject(g, curr); /* won't be collected now */ | ||
| 160 | deadmem += sizeudata(gco2u(curr)); | 147 | deadmem += sizeudata(gco2u(curr)); |
| 161 | markfinalized(gco2u(curr)); | 148 | *p = gch(curr)->next; /* remove 'curr' from 'tmudata' list */ |
| 162 | *p = curr->gch.next; | 149 | /* link 'curr' at the end of 'tobefnz' list */ |
| 163 | /* link `curr' at the end of `tmudata' list */ | 150 | if (g->tobefnz == NULL) /* list is empty? */ |
| 164 | if (g->tmudata == NULL) /* list is empty? */ | 151 | g->tobefnz = gch(curr)->next = curr; /* creates a circular list */ |
| 165 | g->tmudata = curr->gch.next = curr; /* creates a circular list */ | ||
| 166 | else { | 152 | else { |
| 167 | curr->gch.next = g->tmudata->gch.next; | 153 | gch(curr)->next = gch(g->tobefnz)->next; |
| 168 | g->tmudata->gch.next = curr; | 154 | gch(g->tobefnz)->next = curr; |
| 169 | g->tmudata = curr; | 155 | g->tobefnz = curr; |
| 170 | } | 156 | } |
| 171 | } | 157 | } |
| 172 | } | 158 | } |
| @@ -195,7 +181,7 @@ static int traverseephemeron (global_State *g, Table *h) { | |||
| 195 | int hasclears = 0; | 181 | int hasclears = 0; |
| 196 | int i = h->sizearray; | 182 | int i = h->sizearray; |
| 197 | while (i--) { /* mark array part (numeric keys are 'strong') */ | 183 | while (i--) { /* mark array part (numeric keys are 'strong') */ |
| 198 | if (iscollectable(&h->array[i]) && iswhite(gcvalue(&h->array[i]))) { | 184 | if (valiswhite(&h->array[i])) { |
| 199 | marked = 1; | 185 | marked = 1; |
| 200 | reallymarkobject(g, gcvalue(&h->array[i])); | 186 | reallymarkobject(g, gcvalue(&h->array[i])); |
| 201 | } | 187 | } |
| @@ -206,7 +192,7 @@ static int traverseephemeron (global_State *g, Table *h) { | |||
| 206 | lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); | 192 | lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); |
| 207 | if (ttisnil(gval(n))) /* entry is empty? */ | 193 | if (ttisnil(gval(n))) /* entry is empty? */ |
| 208 | removeentry(n); /* remove it */ | 194 | removeentry(n); /* remove it */ |
| 209 | else if (iscollectable(gval(n)) && iswhite(gcvalue(gval(n)))) { | 195 | else if (valiswhite(gval(n))) { |
| 210 | /* value is not marked yet */ | 196 | /* value is not marked yet */ |
| 211 | if (iscleared(key2tval(n), 1)) /* key is not marked (yet)? */ | 197 | if (iscleared(key2tval(n), 1)) /* key is not marked (yet)? */ |
| 212 | hasclears = 1; /* may have to propagate mark from key to value */ | 198 | hasclears = 1; /* may have to propagate mark from key to value */ |
| @@ -256,10 +242,8 @@ static void traversetable (global_State *g, Table *h) { | |||
| 256 | traverseweakvalue(g, h); | 242 | traverseweakvalue(g, h); |
| 257 | else if (!weakvalue) /* strong values? */ | 243 | else if (!weakvalue) /* strong values? */ |
| 258 | traverseephemeron(g, h); | 244 | traverseephemeron(g, h); |
| 259 | else { | 245 | else |
| 260 | lua_assert(weakkey && weakvalue); /* nothing to traverse now */ | 246 | linktable(h, &g->allweak); /* nothing to traverse now */ |
| 261 | linktable(h, &g->allweak); | ||
| 262 | } | ||
| 263 | return; | 247 | return; |
| 264 | } /* else go through */ | 248 | } /* else go through */ |
| 265 | } | 249 | } |
| @@ -350,9 +334,9 @@ static l_mem propagatemark (global_State *g) { | |||
| 350 | GCObject *o = g->gray; | 334 | GCObject *o = g->gray; |
| 351 | lua_assert(isgray(o)); | 335 | lua_assert(isgray(o)); |
| 352 | gray2black(o); | 336 | gray2black(o); |
| 353 | switch (o->gch.tt) { | 337 | switch (gch(o)->tt) { |
| 354 | case LUA_TTABLE: { | 338 | case LUA_TTABLE: { |
| 355 | Table *h = gco2h(o); | 339 | Table *h = gco2t(o); |
| 356 | g->gray = h->gclist; | 340 | g->gray = h->gclist; |
| 357 | traversetable(g, h); | 341 | traversetable(g, h); |
| 358 | return sizeof(Table) + sizeof(TValue) * h->sizearray + | 342 | return sizeof(Table) + sizeof(TValue) * h->sizearray + |
| @@ -406,8 +390,8 @@ static void convergeephemerons (global_State *g) { | |||
| 406 | g->ephemeron = NULL; | 390 | g->ephemeron = NULL; |
| 407 | changed = 0; | 391 | changed = 0; |
| 408 | while ((w = next) != NULL) { | 392 | while ((w = next) != NULL) { |
| 409 | next = gco2h(w)->gclist; | 393 | next = gco2t(w)->gclist; |
| 410 | if (traverseephemeron(g, gco2h(w))) { | 394 | if (traverseephemeron(g, gco2t(w))) { |
| 411 | changed = 1; | 395 | changed = 1; |
| 412 | propagateall(g); | 396 | propagateall(g); |
| 413 | } | 397 | } |
| @@ -422,7 +406,7 @@ static void convergeephemerons (global_State *g) { | |||
| 422 | */ | 406 | */ |
| 423 | static void cleartable (GCObject *l) { | 407 | static void cleartable (GCObject *l) { |
| 424 | while (l) { | 408 | while (l) { |
| 425 | Table *h = gco2h(l); | 409 | Table *h = gco2t(l); |
| 426 | int i = h->sizearray; | 410 | int i = h->sizearray; |
| 427 | while (i--) { | 411 | while (i--) { |
| 428 | TValue *o = &h->array[i]; | 412 | TValue *o = &h->array[i]; |
| @@ -444,25 +428,18 @@ static void cleartable (GCObject *l) { | |||
| 444 | 428 | ||
| 445 | 429 | ||
| 446 | static void freeobj (lua_State *L, GCObject *o) { | 430 | static void freeobj (lua_State *L, GCObject *o) { |
| 447 | switch (o->gch.tt) { | 431 | switch (gch(o)->tt) { |
| 448 | case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; | 432 | case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; |
| 449 | case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; | 433 | case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; |
| 450 | case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; | 434 | case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; |
| 451 | case LUA_TTABLE: luaH_free(L, gco2h(o)); break; | 435 | case LUA_TTABLE: luaH_free(L, gco2t(o)); break; |
| 452 | case LUA_TTHREAD: { | 436 | case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; |
| 453 | lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread); | 437 | case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; |
| 454 | luaE_freethread(L, gco2th(o)); | ||
| 455 | break; | ||
| 456 | } | ||
| 457 | case LUA_TSTRING: { | 438 | case LUA_TSTRING: { |
| 458 | G(L)->strt.nuse--; | 439 | G(L)->strt.nuse--; |
| 459 | luaM_freemem(L, o, sizestring(gco2ts(o))); | 440 | luaM_freemem(L, o, sizestring(gco2ts(o))); |
| 460 | break; | 441 | break; |
| 461 | } | 442 | } |
| 462 | case LUA_TUSERDATA: { | ||
| 463 | luaM_freemem(L, o, sizeudata(gco2u(o))); | ||
| 464 | break; | ||
| 465 | } | ||
| 466 | default: lua_assert(0); | 443 | default: lua_assert(0); |
| 467 | } | 444 | } |
| 468 | } | 445 | } |
| @@ -477,18 +454,16 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { | |||
| 477 | global_State *g = G(L); | 454 | global_State *g = G(L); |
| 478 | int deadmask = otherwhite(g); | 455 | int deadmask = otherwhite(g); |
| 479 | while ((curr = *p) != NULL && count-- > 0) { | 456 | while ((curr = *p) != NULL && count-- > 0) { |
| 480 | if (curr->gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */ | 457 | if (ttisthread(gch(curr))) /* sweep open upvalues of each thread */ |
| 481 | sweepwholelist(L, &gco2th(curr)->openupval); | 458 | sweepwholelist(L, &gco2th(curr)->openupval); |
| 482 | if ((curr->gch.marked ^ WHITEBITS) & deadmask) { /* not dead? */ | 459 | if ((gch(curr)->marked ^ WHITEBITS) & deadmask) { /* not dead? */ |
| 483 | lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT)); | 460 | lua_assert(!isdead(g, curr) || testbit(gch(curr)->marked, FIXEDBIT)); |
| 484 | makewhite(g, curr); /* make it white (for next cycle) */ | 461 | makewhite(g, curr); /* make it white (for next cycle) */ |
| 485 | p = &curr->gch.next; | 462 | p = &gch(curr)->next; |
| 486 | } | 463 | } |
| 487 | else { /* must erase `curr' */ | 464 | else { /* must erase `curr' */ |
| 488 | lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); | 465 | lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); |
| 489 | *p = curr->gch.next; | 466 | *p = gch(curr)->next; /* remove 'curr' from list */ |
| 490 | if (curr == g->rootgc) /* is the first element of the list? */ | ||
| 491 | g->rootgc = curr->gch.next; /* adjust first */ | ||
| 492 | freeobj(L, curr); | 467 | freeobj(L, curr); |
| 493 | } | 468 | } |
| 494 | } | 469 | } |
| @@ -496,6 +471,15 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { | |||
| 496 | } | 471 | } |
| 497 | 472 | ||
| 498 | 473 | ||
| 474 | static GCObject **unmarklist (global_State *g, GCObject **p, lu_mem count) { | ||
| 475 | for (; *p != NULL && count-- > 0; p = &gch(*p)->next) { | ||
| 476 | lua_assert(ttisuserdata(gch(*p)) && !isdead(g, *p)); | ||
| 477 | makewhite(g, *p); | ||
| 478 | } | ||
| 479 | return p; | ||
| 480 | } | ||
| 481 | |||
| 482 | |||
| 499 | static void checkSizes (lua_State *L) { | 483 | static void checkSizes (lua_State *L) { |
| 500 | global_State *g = G(L); | 484 | global_State *g = G(L); |
| 501 | if (g->strt.nuse < cast(lu_int32, g->strt.size)) | 485 | if (g->strt.nuse < cast(lu_int32, g->strt.size)) |
| @@ -505,15 +489,16 @@ static void checkSizes (lua_State *L) { | |||
| 505 | 489 | ||
| 506 | 490 | ||
| 507 | static Udata *udata2finalize (global_State *g) { | 491 | static Udata *udata2finalize (global_State *g) { |
| 508 | GCObject *o = g->tmudata->gch.next; /* get first element */ | 492 | GCObject *o = gch(g->tobefnz)->next; /* get first element */ |
| 509 | Udata *udata = rawgco2u(o); | 493 | Udata *udata = rawgco2u(o); |
| 510 | /* remove udata from `tmudata' */ | 494 | /* remove udata from `tobefnz' */ |
| 511 | if (o == g->tmudata) /* last element? */ | 495 | if (o == g->tobefnz) /* last element? */ |
| 512 | g->tmudata = NULL; | 496 | g->tobefnz = NULL; |
| 513 | else | 497 | else |
| 514 | g->tmudata->gch.next = udata->uv.next; | 498 | gch(g->tobefnz)->next = udata->uv.next; |
| 515 | udata->uv.next = g->mainthread->next; /* return it to `root' list */ | 499 | udata->uv.next = g->mainthread->next; /* return it to `root' list */ |
| 516 | g->mainthread->next = o; | 500 | g->mainthread->next = o; |
| 501 | resetbit(udata->uv.marked, SEPARATED); /* mark it as such */ | ||
| 517 | makewhite(g, o); | 502 | makewhite(g, o); |
| 518 | return udata; | 503 | return udata; |
| 519 | } | 504 | } |
| @@ -522,8 +507,8 @@ static Udata *udata2finalize (global_State *g) { | |||
| 522 | static void GCTM (lua_State *L) { | 507 | static void GCTM (lua_State *L) { |
| 523 | global_State *g = G(L); | 508 | global_State *g = G(L); |
| 524 | Udata *udata = udata2finalize(g); | 509 | Udata *udata = udata2finalize(g); |
| 525 | const TValue *tm = fasttm(L, udata->uv.metatable, TM_GC); | 510 | const TValue *tm = gfasttm(g, udata->uv.metatable, TM_GC); |
| 526 | if (tm != NULL) { | 511 | if (tm != NULL && ttisfunction(tm)) { |
| 527 | lu_byte oldah = L->allowhook; | 512 | lu_byte oldah = L->allowhook; |
| 528 | lu_mem oldt = g->GCthreshold; | 513 | lu_mem oldt = g->GCthreshold; |
| 529 | L->allowhook = 0; /* stop debug hooks during GC tag method */ | 514 | L->allowhook = 0; /* stop debug hooks during GC tag method */ |
| @@ -543,15 +528,15 @@ static void GCTM (lua_State *L) { | |||
| 543 | */ | 528 | */ |
| 544 | void luaC_callGCTM (lua_State *L) { | 529 | void luaC_callGCTM (lua_State *L) { |
| 545 | global_State *g = G(L); | 530 | global_State *g = G(L); |
| 546 | GCObject *last = g->tmudata; | 531 | GCObject *last = g->tobefnz; |
| 547 | GCObject *curr; | 532 | GCObject *curr; |
| 548 | if (last == NULL) return; /* empty list? */ | 533 | if (last == NULL) return; /* empty list? */ |
| 549 | do { | 534 | do { |
| 550 | curr = g->tmudata->gch.next; /* element to be collected */ | 535 | curr = gch(g->tobefnz)->next; /* element to be collected */ |
| 551 | GCTM(L); | 536 | GCTM(L); |
| 552 | } while (curr != last); /* go only until original last */ | 537 | } while (curr != last); /* go only until original last */ |
| 553 | /* do not finalize new udata created during previous finalizations */ | 538 | /* do not finalize new udata created during previous finalizations */ |
| 554 | while (g->tmudata) | 539 | while (g->tobefnz) |
| 555 | udata2finalize(g); /* simply remove them from list */ | 540 | udata2finalize(g); /* simply remove them from list */ |
| 556 | } | 541 | } |
| 557 | 542 | ||
| @@ -559,10 +544,16 @@ void luaC_callGCTM (lua_State *L) { | |||
| 559 | void luaC_freeall (lua_State *L) { | 544 | void luaC_freeall (lua_State *L) { |
| 560 | global_State *g = G(L); | 545 | global_State *g = G(L); |
| 561 | int i; | 546 | int i; |
| 562 | g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); /* mask to collect all elements */ | 547 | lua_assert(g->tobefnz == NULL); |
| 548 | /* mask to collect all elements */ | ||
| 549 | g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); | ||
| 563 | sweepwholelist(L, &g->rootgc); | 550 | sweepwholelist(L, &g->rootgc); |
| 551 | lua_assert(g->rootgc == obj2gco(L)); | ||
| 552 | sweepwholelist(L, &g->tmudata); | ||
| 553 | lua_assert(g->tmudata == NULL); | ||
| 564 | for (i = 0; i < g->strt.size; i++) /* free all string lists */ | 554 | for (i = 0; i < g->strt.size; i++) /* free all string lists */ |
| 565 | sweepwholelist(L, &g->strt.hash[i]); | 555 | sweepwholelist(L, &g->strt.hash[i]); |
| 556 | lua_assert(g->strt.nuse == 0); | ||
| 566 | } | 557 | } |
| 567 | 558 | ||
| 568 | 559 | ||
| @@ -573,6 +564,20 @@ static void markmt (global_State *g) { | |||
| 573 | } | 564 | } |
| 574 | 565 | ||
| 575 | 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 | |||
| 576 | /* mark root set */ | 581 | /* mark root set */ |
| 577 | static void markroot (lua_State *L) { | 582 | static void markroot (lua_State *L) { |
| 578 | global_State *g = G(L); | 583 | global_State *g = G(L); |
| @@ -584,6 +589,7 @@ static void markroot (lua_State *L) { | |||
| 584 | markvalue(g, gt(g->mainthread)); | 589 | markvalue(g, gt(g->mainthread)); |
| 585 | markvalue(g, registry(L)); | 590 | markvalue(g, registry(L)); |
| 586 | markmt(g); | 591 | markmt(g); |
| 592 | markbeingfnz(g); /* mark any finalizing userdata left from previous cycle */ | ||
| 587 | g->gcstate = GCSpropagate; | 593 | g->gcstate = GCSpropagate; |
| 588 | } | 594 | } |
| 589 | 595 | ||
| @@ -598,6 +604,14 @@ static void remarkupvals (global_State *g) { | |||
| 598 | } | 604 | } |
| 599 | 605 | ||
| 600 | 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 | |||
| 601 | static void atomic (lua_State *L) { | 615 | static void atomic (lua_State *L) { |
| 602 | global_State *g = G(L); | 616 | global_State *g = G(L); |
| 603 | size_t udsize; /* total size of userdata to be finalized */ | 617 | size_t udsize; /* total size of userdata to be finalized */ |
| @@ -612,17 +626,10 @@ static void atomic (lua_State *L) { | |||
| 612 | markobject(g, L); /* mark running thread */ | 626 | markobject(g, L); /* mark running thread */ |
| 613 | markmt(g); /* mark basic metatables (again) */ | 627 | markmt(g); /* mark basic metatables (again) */ |
| 614 | propagateall(g); | 628 | propagateall(g); |
| 615 | /* remark ephemeron tables */ | 629 | marklistofgrays(g, &g->ephemeron); /* remark ephemeron tables */ |
| 616 | g->gray = g->ephemeron; | 630 | marklistofgrays(g, &g->grayagain); /* remark gray again */ |
| 617 | g->ephemeron = NULL; | ||
| 618 | propagateall(g); | ||
| 619 | /* remark gray again */ | ||
| 620 | g->gray = g->grayagain; | ||
| 621 | g->grayagain = NULL; | ||
| 622 | propagateall(g); | ||
| 623 | convergeephemerons(g); | 631 | convergeephemerons(g); |
| 624 | udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ | 632 | udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ |
| 625 | marktmu(g); /* mark `preserved' userdata */ | ||
| 626 | udsize += propagateall(g); /* remark, to propagate `preserveness' */ | 633 | udsize += propagateall(g); /* remark, to propagate `preserveness' */ |
| 627 | convergeephemerons(g); | 634 | convergeephemerons(g); |
| 628 | /* remove collected objects from weak tables */ | 635 | /* remove collected objects from weak tables */ |
| @@ -632,7 +639,6 @@ static void atomic (lua_State *L) { | |||
| 632 | /* flip current white */ | 639 | /* flip current white */ |
| 633 | g->currentwhite = cast_byte(otherwhite(g)); | 640 | g->currentwhite = cast_byte(otherwhite(g)); |
| 634 | g->sweepstrgc = 0; | 641 | g->sweepstrgc = 0; |
| 635 | g->sweepgc = &g->rootgc; | ||
| 636 | g->gcstate = GCSsweepstring; | 642 | g->gcstate = GCSsweepstring; |
| 637 | g->estimate = g->totalbytes - udsize; /* first estimate */ | 643 | g->estimate = g->totalbytes - udsize; /* first estimate */ |
| 638 | } | 644 | } |
| @@ -660,10 +666,20 @@ static l_mem singlestep (lua_State *L) { | |||
| 660 | } | 666 | } |
| 661 | case GCSsweepstring: { | 667 | case GCSsweepstring: { |
| 662 | correctestimate(g, sweepwholelist(L, &g->strt.hash[g->sweepstrgc++])); | 668 | correctestimate(g, sweepwholelist(L, &g->strt.hash[g->sweepstrgc++])); |
| 663 | if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */ | 669 | if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */ |
| 664 | g->gcstate = GCSsweep; /* end sweep-string phase */ | 670 | g->sweepgc = &g->tmudata; |
| 671 | g->gcstate = GCSsweeptmu; /* end sweep-string phase */ | ||
| 672 | } | ||
| 665 | return GCSWEEPCOST; | 673 | return GCSWEEPCOST; |
| 666 | } | 674 | } |
| 675 | case GCSsweeptmu: { | ||
| 676 | g->sweepgc = unmarklist(g, g->sweepgc, GCSWEEPMAX); | ||
| 677 | if (*g->sweepgc == NULL) { /* nothing more to sweep? */ | ||
| 678 | g->sweepgc = &g->rootgc; | ||
| 679 | g->gcstate = GCSsweep; /* sweep all other objects */ | ||
| 680 | } | ||
| 681 | return GCSWEEPMAX*GCSWEEPCOST; | ||
| 682 | } | ||
| 667 | case GCSsweep: { | 683 | case GCSsweep: { |
| 668 | correctestimate(g, g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX)); | 684 | correctestimate(g, g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX)); |
| 669 | if (*g->sweepgc == NULL) /* nothing more to sweep? */ | 685 | if (*g->sweepgc == NULL) /* nothing more to sweep? */ |
| @@ -671,7 +687,7 @@ static l_mem singlestep (lua_State *L) { | |||
| 671 | return GCSWEEPMAX*GCSWEEPCOST; | 687 | return GCSWEEPMAX*GCSWEEPCOST; |
| 672 | } | 688 | } |
| 673 | case GCSfinalize: { | 689 | case GCSfinalize: { |
| 674 | if (g->tmudata) { | 690 | if (g->tobefnz) { |
| 675 | GCTM(L); | 691 | GCTM(L); |
| 676 | if (g->estimate > GCFINALIZECOST) | 692 | if (g->estimate > GCFINALIZECOST) |
| 677 | g->estimate -= GCFINALIZECOST; | 693 | g->estimate -= GCFINALIZECOST; |
| @@ -721,19 +737,17 @@ void luaC_fullgc (lua_State *L, int isemergency) { | |||
| 721 | lua_assert(g->gckind == KGC_NORMAL); | 737 | lua_assert(g->gckind == KGC_NORMAL); |
| 722 | g->gckind = isemergency ? KGC_EMERGENCY : KGC_FORCED; | 738 | g->gckind = isemergency ? KGC_EMERGENCY : KGC_FORCED; |
| 723 | if (g->gcstate <= GCSpropagate) { | 739 | if (g->gcstate <= GCSpropagate) { |
| 724 | /* reset sweep marks to sweep all elements (returning them to white) */ | ||
| 725 | g->sweepstrgc = 0; | ||
| 726 | g->sweepgc = &g->rootgc; | ||
| 727 | /* reset other collector lists */ | 740 | /* reset other collector lists */ |
| 728 | g->gray = NULL; | 741 | g->gray = NULL; |
| 729 | g->grayagain = NULL; | 742 | g->grayagain = NULL; |
| 730 | g->weak = g->ephemeron = g->allweak = NULL; | 743 | g->weak = g->ephemeron = g->allweak = NULL; |
| 744 | g->sweepstrgc = 0; | ||
| 731 | g->gcstate = GCSsweepstring; | 745 | g->gcstate = GCSsweepstring; |
| 732 | } | 746 | } |
| 733 | lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate); | 747 | lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate); |
| 734 | /* finish any pending sweep phase */ | 748 | /* finish any pending sweep phase */ |
| 735 | while (g->gcstate != GCSfinalize) { | 749 | while (g->gcstate != GCSfinalize) { |
| 736 | lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep); | 750 | lua_assert(issweep(g)); |
| 737 | singlestep(L); | 751 | singlestep(L); |
| 738 | } | 752 | } |
| 739 | markroot(L); | 753 | markroot(L); |
| @@ -753,7 +767,7 @@ void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { | |||
| 753 | global_State *g = G(L); | 767 | global_State *g = G(L); |
| 754 | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); | 768 | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); |
| 755 | lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); | 769 | lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); |
| 756 | lua_assert(ttype(&o->gch) != LUA_TTABLE); | 770 | lua_assert(ttype(gch(o)) != LUA_TTABLE); |
| 757 | /* must keep invariant? */ | 771 | /* must keep invariant? */ |
| 758 | if (g->gcstate == GCSpropagate) | 772 | if (g->gcstate == GCSpropagate) |
| 759 | reallymarkobject(g, v); /* restore invariant */ | 773 | reallymarkobject(g, v); /* restore invariant */ |
| @@ -775,17 +789,17 @@ void luaC_barrierback (lua_State *L, Table *t) { | |||
| 775 | 789 | ||
| 776 | void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { | 790 | void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { |
| 777 | global_State *g = G(L); | 791 | global_State *g = G(L); |
| 778 | o->gch.next = g->rootgc; | 792 | gch(o)->marked = luaC_white(g); |
| 793 | gch(o)->tt = tt; | ||
| 794 | gch(o)->next = g->rootgc; | ||
| 779 | g->rootgc = o; | 795 | g->rootgc = o; |
| 780 | o->gch.marked = luaC_white(g); | ||
| 781 | o->gch.tt = tt; | ||
| 782 | } | 796 | } |
| 783 | 797 | ||
| 784 | 798 | ||
| 785 | void luaC_linkupval (lua_State *L, UpVal *uv) { | 799 | void luaC_linkupval (lua_State *L, UpVal *uv) { |
| 786 | global_State *g = G(L); | 800 | global_State *g = G(L); |
| 787 | GCObject *o = obj2gco(uv); | 801 | GCObject *o = obj2gco(uv); |
| 788 | o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ | 802 | gch(o)->next = g->rootgc; /* link upvalue into `rootgc' list */ |
| 789 | g->rootgc = o; | 803 | g->rootgc = o; |
| 790 | if (isgray(o)) { | 804 | if (isgray(o)) { |
| 791 | if (g->gcstate == GCSpropagate) { | 805 | if (g->gcstate == GCSpropagate) { |
| @@ -799,3 +813,22 @@ void luaC_linkupval (lua_State *L, UpVal *uv) { | |||
| 799 | } | 813 | } |
| 800 | } | 814 | } |
| 801 | 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 | |||
| 834 | |||
