diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2004-08-24 17:12:06 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2004-08-24 17:12:06 -0300 |
| commit | 32d4f304db365599a54b3eb30377ac6e20846749 (patch) | |
| tree | eac53658b7ed66e5fe1e96a1e7db93dfea782bbc | |
| parent | 4b12eff8017f5e005a483f8097cdd64e9723a514 (diff) | |
| download | lua-32d4f304db365599a54b3eb30377ac6e20846749.tar.gz lua-32d4f304db365599a54b3eb30377ac6e20846749.tar.bz2 lua-32d4f304db365599a54b3eb30377ac6e20846749.zip | |
first implementation of generational GC
| -rw-r--r-- | lgc.c | 257 | ||||
| -rw-r--r-- | lgc.h | 17 | ||||
| -rw-r--r-- | lstate.c | 10 | ||||
| -rw-r--r-- | lstate.h | 7 | ||||
| -rw-r--r-- | lstring.c | 11 | ||||
| -rw-r--r-- | lstring.h | 3 | ||||
| -rw-r--r-- | ltests.c | 16 |
7 files changed, 162 insertions, 159 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.c,v 2.7 2004/04/30 20:13:38 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.8 2004/08/10 19:17:23 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 | */ |
| @@ -25,10 +25,11 @@ | |||
| 25 | 25 | ||
| 26 | #define GCSTEPSIZE (40*sizeof(TValue)) | 26 | #define GCSTEPSIZE (40*sizeof(TValue)) |
| 27 | #define STEPMUL 2 | 27 | #define STEPMUL 2 |
| 28 | #define GCFREECOST (sizeof(TValue)/10) | 28 | #define GCSWEEPMAX 40 |
| 29 | #define GCSWEEPCOST (sizeof(TValue)/20) | 29 | #define GCSWEEPCOST 1 |
| 30 | #define GCFINALIZECOST (10*sizeof(TValue)) | 30 | #define GCFINALIZECOST (10*sizeof(TValue)) |
| 31 | #define WAITNEXTCYCLE (10 * GCSTEPSIZE) | 31 | #define WAITNEXTCYCLE (40 * GCSTEPSIZE) |
| 32 | #define WAITNEXTCYCLEGN (200 * GCSTEPSIZE) | ||
| 32 | 33 | ||
| 33 | 34 | ||
| 34 | #define FIXEDMASK bitmask(FIXEDBIT) | 35 | #define FIXEDMASK bitmask(FIXEDBIT) |
| @@ -269,60 +270,61 @@ static void traversestack (global_State *g, lua_State *l) { | |||
| 269 | 270 | ||
| 270 | 271 | ||
| 271 | /* | 272 | /* |
| 272 | ** traverse a given `quantity' of gray objects, | 273 | ** traverse one gray object, turning it to black. |
| 273 | ** turning them to black. Returns extra `quantity' traversed. | 274 | ** Returns `quantity' traversed. |
| 274 | */ | 275 | */ |
| 275 | static l_mem propagatemarks (global_State *g, l_mem lim) { | 276 | static l_mem propagatemark (global_State *g) { |
| 276 | GCObject *o; | 277 | GCObject *o = g->gray; |
| 277 | while ((o = g->gray) != NULL) { | 278 | lua_assert(isgray(o)); |
| 278 | lua_assert(isgray(o)); | 279 | gray2black(o); |
| 279 | gray2black(o); | 280 | switch (o->gch.tt) { |
| 280 | switch (o->gch.tt) { | 281 | case LUA_TTABLE: { |
| 281 | case LUA_TTABLE: { | 282 | Table *h = gco2h(o); |
| 282 | Table *h = gco2h(o); | 283 | g->gray = h->gclist; |
| 283 | g->gray = h->gclist; | 284 | if (traversetable(g, h)) /* table is weak? */ |
| 284 | if (traversetable(g, h)) /* table is weak? */ | 285 | black2gray(o); /* keep it gray */ |
| 285 | black2gray(o); /* keep it gray */ | 286 | return sizeof(Table) + sizeof(TValue) * h->sizearray + |
| 286 | lim -= sizeof(Table) + sizeof(TValue) * h->sizearray + | 287 | sizeof(Node) * sizenode(h); |
| 287 | sizeof(Node) * sizenode(h); | 288 | break; |
| 288 | break; | 289 | } |
| 289 | } | 290 | case LUA_TFUNCTION: { |
| 290 | case LUA_TFUNCTION: { | 291 | Closure *cl = gco2cl(o); |
| 291 | Closure *cl = gco2cl(o); | 292 | g->gray = cl->c.gclist; |
| 292 | g->gray = cl->c.gclist; | 293 | traverseclosure(g, cl); |
| 293 | traverseclosure(g, cl); | 294 | return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : |
| 294 | lim -= (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : | 295 | sizeLclosure(cl->l.nupvalues); |
| 295 | sizeLclosure(cl->l.nupvalues); | 296 | break; |
| 296 | break; | ||
| 297 | } | ||
| 298 | case LUA_TTHREAD: { | ||
| 299 | lua_State *th = gco2th(o); | ||
| 300 | g->gray = th->gclist; | ||
| 301 | th->gclist = g->grayagain; | ||
| 302 | g->grayagain = o; | ||
| 303 | black2gray(o); | ||
| 304 | traversestack(g, th); | ||
| 305 | lim -= sizeof(lua_State) + sizeof(TValue) * th->stacksize + | ||
| 306 | sizeof(CallInfo) * th->size_ci; | ||
| 307 | break; | ||
| 308 | } | ||
| 309 | case LUA_TPROTO: { | ||
| 310 | Proto *p = gco2p(o); | ||
| 311 | g->gray = p->gclist; | ||
| 312 | traverseproto(g, p); | ||
| 313 | lim -= sizeof(Proto) + sizeof(Instruction) * p->sizecode + | ||
| 314 | sizeof(Proto *) * p->sizep + | ||
| 315 | sizeof(TValue) * p->sizek + | ||
| 316 | sizeof(int) * p->sizelineinfo + | ||
| 317 | sizeof(LocVar) * p->sizelocvars + | ||
| 318 | sizeof(TString *) * p->sizeupvalues; | ||
| 319 | break; | ||
| 320 | } | ||
| 321 | default: lua_assert(0); | ||
| 322 | } | 297 | } |
| 323 | if (lim <= 0) return lim; | 298 | case LUA_TTHREAD: { |
| 299 | lua_State *th = gco2th(o); | ||
| 300 | g->gray = th->gclist; | ||
| 301 | th->gclist = g->grayagain; | ||
| 302 | g->grayagain = o; | ||
| 303 | black2gray(o); | ||
| 304 | traversestack(g, th); | ||
| 305 | return sizeof(lua_State) + sizeof(TValue) * th->stacksize + | ||
| 306 | sizeof(CallInfo) * th->size_ci; | ||
| 307 | break; | ||
| 308 | } | ||
| 309 | case LUA_TPROTO: { | ||
| 310 | Proto *p = gco2p(o); | ||
| 311 | g->gray = p->gclist; | ||
| 312 | traverseproto(g, p); | ||
| 313 | return sizeof(Proto) + sizeof(Instruction) * p->sizecode + | ||
| 314 | sizeof(Proto *) * p->sizep + | ||
| 315 | sizeof(TValue) * p->sizek + | ||
| 316 | sizeof(int) * p->sizelineinfo + | ||
| 317 | sizeof(LocVar) * p->sizelocvars + | ||
| 318 | sizeof(TString *) * p->sizeupvalues; | ||
| 319 | break; | ||
| 320 | } | ||
| 321 | default: lua_assert(0); return 0; | ||
| 324 | } | 322 | } |
| 325 | return lim; | 323 | } |
| 324 | |||
| 325 | |||
| 326 | static void propagateall (global_State *g) { | ||
| 327 | while (g->gray) propagatemark(g); | ||
| 326 | } | 328 | } |
| 327 | 329 | ||
| 328 | 330 | ||
| @@ -384,6 +386,7 @@ static void freeobj (lua_State *L, GCObject *o) { | |||
| 384 | break; | 386 | break; |
| 385 | } | 387 | } |
| 386 | case LUA_TSTRING: { | 388 | case LUA_TSTRING: { |
| 389 | G(L)->strt.nuse--; | ||
| 387 | luaM_free(L, o, sizestring(gco2ts(o)->len)); | 390 | luaM_free(L, o, sizestring(gco2ts(o)->len)); |
| 388 | break; | 391 | break; |
| 389 | } | 392 | } |
| @@ -396,59 +399,50 @@ static void freeobj (lua_State *L, GCObject *o) { | |||
| 396 | } | 399 | } |
| 397 | 400 | ||
| 398 | 401 | ||
| 399 | static l_mem sweepwholelist (lua_State *L, GCObject **p, int keepfixed, | 402 | |
| 400 | lu_int32 *count); | 403 | #define sweepwholelist(L,p) sweeplist(L,p,LUA_MAXINT32) |
| 401 | 404 | ||
| 402 | 405 | ||
| 403 | static GCObject **sweeplist (lua_State *L, GCObject **p, int keepfixed, | 406 | static GCObject **sweeplist (lua_State *L, GCObject **p, lu_int32 count) { |
| 404 | l_mem *plim, lu_int32 *count) { | ||
| 405 | GCObject *curr; | 407 | GCObject *curr; |
| 406 | global_State *g = G(L); | 408 | global_State *g = G(L); |
| 407 | l_mem lim = *plim; | 409 | int whitebit = otherwhite(g); |
| 408 | int deadmask = otherwhite(g); | 410 | int deadmask = whitebit | FIXEDMASK; |
| 409 | if (keepfixed) deadmask |= FIXEDMASK; | ||
| 410 | while ((curr = *p) != NULL) { | 411 | while ((curr = *p) != NULL) { |
| 411 | if (((curr->gch.marked ^ FIXEDMASK) & deadmask) != deadmask) { | 412 | if ((curr->gch.marked ^ whitebit) & deadmask) { |
| 412 | makewhite(g, curr); | 413 | lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT)); |
| 414 | if (!G(L)->gcgenerational || isdead(g, curr)) | ||
| 415 | makewhite(g, curr); | ||
| 413 | if (curr->gch.tt == LUA_TTHREAD) | 416 | if (curr->gch.tt == LUA_TTHREAD) |
| 414 | lim -= sweepwholelist(L, &gco2th(curr)->openupval, keepfixed, count); | 417 | sweepwholelist(L, &gco2th(curr)->openupval); |
| 415 | p = &curr->gch.next; | 418 | p = &curr->gch.next; |
| 416 | lim -= GCSWEEPCOST; | ||
| 417 | } | 419 | } |
| 418 | else { | 420 | else { |
| 419 | lua_assert(iswhite(curr)); | 421 | lua_assert(isdead(g, curr)); |
| 420 | *p = curr->gch.next; | 422 | *p = curr->gch.next; |
| 421 | if (curr == g->rootgc) /* is the first element of the list? */ | 423 | if (curr == g->rootgc) /* is the first element of the list? */ |
| 422 | g->rootgc = curr->gch.next; /* adjust first */ | 424 | g->rootgc = curr->gch.next; /* adjust first */ |
| 423 | freeobj(L, curr); | 425 | freeobj(L, curr); |
| 424 | lim -= GCFREECOST; | ||
| 425 | if (count) (*count)--; | ||
| 426 | } | 426 | } |
| 427 | if (lim <= 0) break; | 427 | if (count-- == 0) break; |
| 428 | } | 428 | } |
| 429 | *plim = lim; | ||
| 430 | return p; | 429 | return p; |
| 431 | } | 430 | } |
| 432 | 431 | ||
| 433 | 432 | ||
| 434 | static l_mem sweepwholelist (lua_State *L, GCObject **p, int keepfixed, | 433 | static void sweepstrings (lua_State *L) { |
| 435 | lu_int32 *count) { | 434 | global_State *g = G(L); |
| 436 | l_mem lim = MAXLMEM; | 435 | sweepwholelist(L, &G(L)->strt.hash[g->sweepstrgc++]); |
| 437 | /* empty lists are quite common here, so avoid useless calls */ | ||
| 438 | if (*p) sweeplist(L, p, keepfixed, &lim, count); | ||
| 439 | return MAXLMEM - lim; | ||
| 440 | } | 436 | } |
| 441 | 437 | ||
| 442 | 438 | ||
| 443 | static l_mem sweepstrings (lua_State *L, int keepfixed, l_mem lim) { | 439 | static void freelist (lua_State *L, GCObject **p) { |
| 444 | int i; | 440 | while (*p) { |
| 445 | global_State *g = G(L); | 441 | GCObject *curr = *p; |
| 446 | for (i = g->sweepstrgc; i < g->strt.size; i++) { /* for each list */ | 442 | *p = (*p)->gch.next; |
| 447 | lim -= sweepwholelist(L, &G(L)->strt.hash[i], keepfixed, &g->strt.nuse); | 443 | if (curr != obj2gco(L)) |
| 448 | if (lim <= 0) break; | 444 | freeobj(L, curr); |
| 449 | } | 445 | } |
| 450 | g->sweepstrgc = i+1; | ||
| 451 | return lim; | ||
| 452 | } | 446 | } |
| 453 | 447 | ||
| 454 | 448 | ||
| @@ -497,19 +491,12 @@ void luaC_callGCTM (lua_State *L) { | |||
| 497 | } | 491 | } |
| 498 | 492 | ||
| 499 | 493 | ||
| 500 | void luaC_sweepall (lua_State *L) { | 494 | void luaC_freeall (lua_State *L) { |
| 501 | global_State *g = G(L); | 495 | global_State *g = G(L); |
| 502 | l_mem dummy = MAXLMEM; | 496 | int i; |
| 503 | /* finish (occasional) current sweep */ | 497 | freelist(L, &g->rootgc); |
| 504 | sweepstrings(L, 0, MAXLMEM); | 498 | for (i = 0; i < g->strt.size; i++) /* free all string lists */ |
| 505 | sweeplist(L, &g->rootgc, 0, &dummy, NULL); | 499 | freelist(L, &G(L)->strt.hash[i]); |
| 506 | /* do a whole new sweep */ | ||
| 507 | markobject(g, g->mainthread); /* cannot collect main thread */ | ||
| 508 | g->currentwhite = otherwhite(g); | ||
| 509 | g->sweepgc = &g->rootgc; | ||
| 510 | g->sweepstrgc = 0; | ||
| 511 | sweepstrings(L, 0, MAXLMEM); | ||
| 512 | sweeplist(L, &g->rootgc, 0, &dummy, NULL); | ||
| 513 | } | 500 | } |
| 514 | 501 | ||
| 515 | 502 | ||
| @@ -553,64 +540,68 @@ static void atomic (lua_State *L) { | |||
| 553 | g->weak = NULL; | 540 | g->weak = NULL; |
| 554 | lua_assert(!iswhite(obj2gco(g->mainthread))); | 541 | lua_assert(!iswhite(obj2gco(g->mainthread))); |
| 555 | markobject(g, L); /* mark running thread */ | 542 | markobject(g, L); /* mark running thread */ |
| 556 | propagatemarks(g, MAXLMEM); | 543 | propagateall(g); |
| 557 | /* remark gray again */ | 544 | /* remark gray again */ |
| 558 | g->gray = g->grayagain; | 545 | g->gray = g->grayagain; |
| 559 | g->grayagain = NULL; | 546 | g->grayagain = NULL; |
| 560 | propagatemarks(g, MAXLMEM); | 547 | propagateall(g); |
| 561 | luaC_separateudata(L, 0); /* separate userdata to be preserved */ | 548 | luaC_separateudata(L, 0); /* separate userdata to be preserved */ |
| 562 | marktmu(g); /* mark `preserved' userdata */ | 549 | marktmu(g); /* mark `preserved' userdata */ |
| 563 | propagatemarks(g, MAXLMEM); /* remark, to propagate `preserveness' */ | 550 | propagateall(g); /* remark, to propagate `preserveness' */ |
| 564 | cleartable(g->weak); /* remove collected objects from weak tables */ | 551 | cleartable(g->weak); /* remove collected objects from weak tables */ |
| 565 | /* flip current white */ | 552 | /* flip current white */ |
| 566 | g->currentwhite = otherwhite(g); | 553 | g->currentwhite = otherwhite(g); |
| 554 | g->sweepstrgc = 0; | ||
| 555 | g->sweepgc = &g->rootgc; | ||
| 567 | g->gcstate = GCSsweepstring; | 556 | g->gcstate = GCSsweepstring; |
| 557 | if (g->gcgenerational++ > 20) g->gcgenerational = 0; | ||
| 568 | } | 558 | } |
| 569 | 559 | ||
| 570 | 560 | ||
| 571 | static l_mem singlestep (lua_State *L, l_mem lim) { | 561 | static l_mem singlestep (lua_State *L) { |
| 572 | global_State *g = G(L); | 562 | global_State *g = G(L); |
| 563 | /*lua_checkmemory(L);*/ | ||
| 573 | switch (g->gcstate) { | 564 | switch (g->gcstate) { |
| 574 | case GCSpropagate: { | 565 | case GCSpropagate: { |
| 575 | if (g->gray) | 566 | if (g->gray) |
| 576 | lim = propagatemarks(g, lim); | 567 | return propagatemark(g); |
| 577 | else { /* no more `gray' objects */ | 568 | else { /* no more `gray' objects */ |
| 578 | atomic(L); /* finish mark phase */ | 569 | atomic(L); /* finish mark phase */ |
| 579 | lim = 0; | 570 | return 0; |
| 580 | } | 571 | } |
| 581 | break; | ||
| 582 | } | 572 | } |
| 583 | case GCSsweepstring: { | 573 | case GCSsweepstring: { |
| 584 | lim = sweepstrings(L, 1, lim); | 574 | sweepstrings(L); |
| 585 | if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */ | 575 | if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */ |
| 586 | g->sweepstrgc = 0; | ||
| 587 | g->gcstate = GCSsweep; /* end sweep-string phase */ | 576 | g->gcstate = GCSsweep; /* end sweep-string phase */ |
| 588 | } | 577 | return GCSWEEPCOST; |
| 589 | break; | ||
| 590 | } | 578 | } |
| 591 | case GCSsweep: { | 579 | case GCSsweep: { |
| 592 | g->sweepgc = sweeplist(L, g->sweepgc, 1, &lim, NULL); | 580 | g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); |
| 593 | if (*g->sweepgc == NULL) { /* nothing more to sweep? */ | 581 | if (*g->sweepgc == NULL) { /* nothing more to sweep? */ |
| 594 | checkSizes(L); | 582 | checkSizes(L); |
| 595 | g->sweepgc = &g->rootgc; | ||
| 596 | g->gcstate = GCSfinalize; /* end sweep phase */ | 583 | g->gcstate = GCSfinalize; /* end sweep phase */ |
| 597 | } | 584 | } |
| 598 | break; | 585 | return GCSWEEPCOST; |
| 599 | } | 586 | } |
| 600 | case GCSfinalize: { | 587 | case GCSfinalize: { |
| 601 | if (g->tmudata) { | 588 | if (g->tmudata) { |
| 602 | GCTM(L); | 589 | GCTM(L); |
| 603 | lim -= GCFINALIZECOST; | 590 | return GCFINALIZECOST; |
| 604 | } | 591 | } |
| 605 | else { /* no more `udata' to finalize */ | 592 | else { /* no more `udata' to finalize */ |
| 606 | markroot(L); /* may restart collection */ | 593 | if (g->gcgenerational) { |
| 607 | lim = 0; | 594 | atomic(L); |
| 595 | return WAITNEXTCYCLEGN; | ||
| 596 | } | ||
| 597 | else { | ||
| 598 | markroot(L); /* may restart collection */ | ||
| 599 | return WAITNEXTCYCLE; | ||
| 600 | } | ||
| 608 | } | 601 | } |
| 609 | break; | ||
| 610 | } | 602 | } |
| 611 | default: lua_assert(0); | 603 | default: lua_assert(0); return 0; |
| 612 | } | 604 | } |
| 613 | return lim; | ||
| 614 | } | 605 | } |
| 615 | 606 | ||
| 616 | 607 | ||
| @@ -618,11 +609,7 @@ void luaC_step (lua_State *L) { | |||
| 618 | global_State *g = G(L); | 609 | global_State *g = G(L); |
| 619 | l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * STEPMUL; | 610 | l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * STEPMUL; |
| 620 | do { | 611 | do { |
| 621 | lim = singlestep(L, lim); | 612 | lim -= singlestep(L); |
| 622 | if (g->gcstate == GCSfinalize && g->tmudata == NULL) { | ||
| 623 | lim = -WAITNEXTCYCLE; | ||
| 624 | break; /* do not start new collection */ | ||
| 625 | } | ||
| 626 | } while (lim > 0); | 613 | } while (lim > 0); |
| 627 | g->GCthreshold = g->nblocks + GCSTEPSIZE - lim/STEPMUL; | 614 | g->GCthreshold = g->nblocks + GCSTEPSIZE - lim/STEPMUL; |
| 628 | lua_assert((long)g->nblocks + (long)GCSTEPSIZE >= lim/STEPMUL); | 615 | lua_assert((long)g->nblocks + (long)GCSTEPSIZE >= lim/STEPMUL); |
| @@ -631,12 +618,26 @@ void luaC_step (lua_State *L) { | |||
| 631 | 618 | ||
| 632 | void luaC_fullgc (lua_State *L) { | 619 | void luaC_fullgc (lua_State *L) { |
| 633 | global_State *g = G(L); | 620 | global_State *g = G(L); |
| 621 | if (g->gcstate == GCSpropagate || g->gcgenerational) { | ||
| 622 | g->gcgenerational = 0; | ||
| 623 | /* reset sweep marks to sweep all elements (returning them to white) */ | ||
| 624 | g->sweepstrgc = 0; | ||
| 625 | g->sweepgc = &g->rootgc; | ||
| 626 | /* reset other collector lists */ | ||
| 627 | g->gray = NULL; | ||
| 628 | g->grayagain = NULL; | ||
| 629 | g->weak = NULL; | ||
| 630 | g->gcstate = GCSsweepstring; | ||
| 631 | } | ||
| 632 | /* finish any pending sweep phase */ | ||
| 634 | while (g->gcstate != GCSfinalize) { | 633 | while (g->gcstate != GCSfinalize) { |
| 635 | singlestep(L, MAXLMEM); | 634 | singlestep(L); |
| 636 | } | 635 | } |
| 637 | markroot(L); | 636 | markroot(L); |
| 637 | lua_assert(!g->gcgenerational); | ||
| 638 | while (g->gcstate != GCSfinalize) { | 638 | while (g->gcstate != GCSfinalize) { |
| 639 | singlestep(L, MAXLMEM); | 639 | singlestep(L); |
| 640 | g->gcgenerational = 0; /* keep it in this mode */ | ||
| 640 | } | 641 | } |
| 641 | g->GCthreshold = g->nblocks + GCSTEPSIZE; | 642 | g->GCthreshold = g->nblocks + GCSTEPSIZE; |
| 642 | luaC_callGCTM(L); /* call finalizers */ | 643 | luaC_callGCTM(L); /* call finalizers */ |
| @@ -646,7 +647,7 @@ void luaC_fullgc (lua_State *L) { | |||
| 646 | void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { | 647 | void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { |
| 647 | global_State *g = G(L); | 648 | global_State *g = G(L); |
| 648 | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); | 649 | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); |
| 649 | lua_assert(g->gcstate != GCSfinalize); | 650 | lua_assert(g->gcgenerational || g->gcstate != GCSfinalize); |
| 650 | if (g->gcstate != GCSpropagate) /* sweeping phases? */ | 651 | if (g->gcstate != GCSpropagate) /* sweeping phases? */ |
| 651 | black2gray(o); /* just mark as gray to avoid other barriers */ | 652 | black2gray(o); /* just mark as gray to avoid other barriers */ |
| 652 | else /* breaking invariant! */ | 653 | else /* breaking invariant! */ |
| @@ -657,7 +658,7 @@ void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { | |||
| 657 | void luaC_barrierback (lua_State *L, GCObject *o, GCObject *v) { | 658 | void luaC_barrierback (lua_State *L, GCObject *o, GCObject *v) { |
| 658 | global_State *g = G(L); | 659 | global_State *g = G(L); |
| 659 | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); | 660 | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); |
| 660 | lua_assert(g->gcstate != GCSfinalize); | 661 | lua_assert(g->gcgenerational || g->gcstate != GCSfinalize); |
| 661 | black2gray(o); /* make table gray (again) */ | 662 | black2gray(o); /* make table gray (again) */ |
| 662 | gco2h(o)->gclist = g->grayagain; | 663 | gco2h(o)->gclist = g->grayagain; |
| 663 | g->grayagain = o; | 664 | g->grayagain = o; |
| @@ -679,7 +680,7 @@ void luaC_linkupval (lua_State *L, UpVal *uv) { | |||
| 679 | o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ | 680 | o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ |
| 680 | g->rootgc = o; | 681 | g->rootgc = o; |
| 681 | if (isgray(o)) { | 682 | if (isgray(o)) { |
| 682 | if (g->gcstate == GCSpropagate) { | 683 | if (g->gcstate == GCSpropagate || g->gcgenerational) { |
| 683 | gray2black(o); /* closed upvalues need barrier */ | 684 | gray2black(o); /* closed upvalues need barrier */ |
| 684 | luaC_barrier(L, uv, uv->v); | 685 | luaC_barrier(L, uv, uv->v); |
| 685 | } | 686 | } |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.h,v 2.5 2004/03/15 21:04:33 roberto Exp roberto $ | 2 | ** $Id: lgc.h,v 2.6 2004/08/10 19:17:23 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 | */ |
| @@ -39,12 +39,13 @@ | |||
| 39 | 39 | ||
| 40 | /* | 40 | /* |
| 41 | ** Layout for bit use in `marked' field: | 41 | ** Layout for bit use in `marked' field: |
| 42 | ** bit 0 - object is gray | 42 | ** bit 0 - object is white (type 0) |
| 43 | ** bit 1 - object is black | 43 | ** bit 1 - object is white (type 1) |
| 44 | ** bit 2 - For userdata: is finalized; | 44 | ** bit 2 - object is black |
| 45 | for tables: has weak keys | 45 | ** bit 3 - for userdata: has been finalized |
| 46 | ** bit 3 - for tables: has weak values | 46 | ** bit 3 - for tables: has weak keys |
| 47 | ** bit 4 - object is fixed (should not be collected) | 47 | ** bit 4 - for tables: has weak values |
| 48 | ** bit 5 - object is fixed (should not be collected) | ||
| 48 | */ | 49 | */ |
| 49 | 50 | ||
| 50 | #define WHITE0BIT 0 | 51 | #define WHITE0BIT 0 |
| @@ -86,7 +87,7 @@ | |||
| 86 | 87 | ||
| 87 | size_t luaC_separateudata (lua_State *L, int all); | 88 | size_t luaC_separateudata (lua_State *L, int all); |
| 88 | void luaC_callGCTM (lua_State *L); | 89 | void luaC_callGCTM (lua_State *L); |
| 89 | void luaC_sweepall (lua_State *L); | 90 | void luaC_freeall (lua_State *L); |
| 90 | void luaC_step (lua_State *L); | 91 | void luaC_step (lua_State *L); |
| 91 | void luaC_fullgc (lua_State *L); | 92 | void luaC_fullgc (lua_State *L); |
| 92 | void luaC_link (lua_State *L, GCObject *o, lu_byte tt); | 93 | void luaC_link (lua_State *L, GCObject *o, lu_byte tt); |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstate.c,v 2.9 2004/06/17 14:06:52 roberto Exp roberto $ | 2 | ** $Id: lstate.c,v 2.10 2004/06/17 14:25:31 roberto Exp roberto $ |
| 3 | ** Global State | 3 | ** Global State |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -122,9 +122,10 @@ static void preinit_state (lua_State *L, global_State *g) { | |||
| 122 | static void close_state (lua_State *L) { | 122 | static void close_state (lua_State *L) { |
| 123 | global_State *g = G(L); | 123 | global_State *g = G(L); |
| 124 | luaF_close(L, L->stack); /* close all upvalues for this thread */ | 124 | luaF_close(L, L->stack); /* close all upvalues for this thread */ |
| 125 | luaC_sweepall(L); /* collect all elements */ | 125 | luaC_freeall(L); /* collect all objects */ |
| 126 | lua_assert(g->rootgc == obj2gco(L)); | 126 | lua_assert(g->rootgc == NULL); |
| 127 | luaS_freeall(L); | 127 | lua_assert(g->strt.nuse == 0); |
| 128 | luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *); | ||
| 128 | luaZ_freebuffer(L, &g->buff); | 129 | luaZ_freebuffer(L, &g->buff); |
| 129 | freestack(L, L); | 130 | freestack(L, L); |
| 130 | lua_assert(g->nblocks == sizeof(LG)); | 131 | lua_assert(g->nblocks == sizeof(LG)); |
| @@ -177,6 +178,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
| 177 | luaZ_initbuffer(L, &g->buff); | 178 | luaZ_initbuffer(L, &g->buff); |
| 178 | g->panic = NULL; | 179 | g->panic = NULL; |
| 179 | g->gcstate = GCSfinalize; | 180 | g->gcstate = GCSfinalize; |
| 181 | g->gcgenerational = 0; | ||
| 180 | g->rootgc = obj2gco(L); | 182 | g->rootgc = obj2gco(L); |
| 181 | g->sweepstrgc = 0; | 183 | g->sweepstrgc = 0; |
| 182 | g->sweepgc = &g->rootgc; | 184 | g->sweepgc = &g->rootgc; |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstate.h,v 2.4 2004/05/31 18:51:50 roberto Exp roberto $ | 2 | ** $Id: lstate.h,v 2.5 2004/06/02 19:07:55 roberto Exp roberto $ |
| 3 | ** Global State | 3 | ** Global State |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -69,7 +69,9 @@ typedef struct global_State { | |||
| 69 | stringtable strt; /* hash table for strings */ | 69 | stringtable strt; /* hash table for strings */ |
| 70 | lua_Alloc realloc; /* function to reallocate memory */ | 70 | lua_Alloc realloc; /* function to reallocate memory */ |
| 71 | void *ud; /* auxiliary data to `realloc' */ | 71 | void *ud; /* auxiliary data to `realloc' */ |
| 72 | int currentwhite; | 72 | lu_byte currentwhite; |
| 73 | lu_byte gcstate; /* state of garbage collector */ | ||
| 74 | lu_byte gcgenerational; | ||
| 73 | GCObject *rootgc; /* list of all collectable objects */ | 75 | GCObject *rootgc; /* list of all collectable objects */ |
| 74 | GCObject *firstudata; /* udata go to the end of `rootgc' */ | 76 | GCObject *firstudata; /* udata go to the end of `rootgc' */ |
| 75 | GCObject **sweepgc; /* position of sweep in `rootgc' */ | 77 | GCObject **sweepgc; /* position of sweep in `rootgc' */ |
| @@ -78,7 +80,6 @@ typedef struct global_State { | |||
| 78 | GCObject *grayagain; /* list of objects to be traversed atomically */ | 80 | GCObject *grayagain; /* list of objects to be traversed atomically */ |
| 79 | GCObject *weak; /* list of weak tables (to be cleared) */ | 81 | GCObject *weak; /* list of weak tables (to be cleared) */ |
| 80 | GCObject *tmudata; /* list of userdata to be GC */ | 82 | GCObject *tmudata; /* list of userdata to be GC */ |
| 81 | int gcstate; /* state of garbage collector */ | ||
| 82 | Mbuffer buff; /* temporary buffer for string concatentation */ | 83 | Mbuffer buff; /* temporary buffer for string concatentation */ |
| 83 | lu_mem GCthreshold; | 84 | lu_mem GCthreshold; |
| 84 | lu_mem nblocks; /* number of `bytes' currently allocated */ | 85 | lu_mem nblocks; /* number of `bytes' currently allocated */ |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstring.c,v 2.1 2003/12/10 12:13:36 roberto Exp roberto $ | 2 | ** $Id: lstring.c,v 2.2 2004/04/30 20:13:38 roberto Exp roberto $ |
| 3 | ** String table (keeps all strings handled by Lua) | 3 | ** String table (keeps all strings handled by Lua) |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -19,17 +19,12 @@ | |||
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | void luaS_freeall (lua_State *L) { | ||
| 23 | lua_assert(G(L)->strt.nuse==0); | ||
| 24 | luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *); | ||
| 25 | } | ||
| 26 | |||
| 27 | |||
| 28 | void luaS_resize (lua_State *L, int newsize) { | 22 | void luaS_resize (lua_State *L, int newsize) { |
| 29 | GCObject **newhash; | 23 | GCObject **newhash; |
| 30 | stringtable *tb; | 24 | stringtable *tb; |
| 31 | int i; | 25 | int i; |
| 32 | if (G(L)->sweepstrgc > 0) return; /* cannot resize during GC traverse */ | 26 | if (G(L)->gcstate == GCSsweepstring) |
| 27 | return; /* cannot resize during GC traverse */ | ||
| 33 | newhash = luaM_newvector(L, newsize, GCObject *); | 28 | newhash = luaM_newvector(L, newsize, GCObject *); |
| 34 | tb = &G(L)->strt; | 29 | tb = &G(L)->strt; |
| 35 | for (i=0; i<newsize; i++) newhash[i] = NULL; | 30 | for (i=0; i<newsize; i++) newhash[i] = NULL; |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstring.h,v 1.37 2002/08/16 14:45:55 roberto Exp roberto $ | 2 | ** $Id: lstring.h,v 1.38 2003/11/17 19:50:05 roberto Exp roberto $ |
| 3 | ** String table (keep all strings handled by Lua) | 3 | ** String table (keep all strings handled by Lua) |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -26,7 +26,6 @@ | |||
| 26 | 26 | ||
| 27 | void luaS_resize (lua_State *L, int newsize); | 27 | void luaS_resize (lua_State *L, int newsize); |
| 28 | Udata *luaS_newudata (lua_State *L, size_t s); | 28 | Udata *luaS_newudata (lua_State *L, size_t s); |
| 29 | void luaS_freeall (lua_State *L); | ||
| 30 | TString *luaS_newlstr (lua_State *L, const char *str, size_t l); | 29 | TString *luaS_newlstr (lua_State *L, const char *str, size_t l); |
| 31 | 30 | ||
| 32 | 31 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ltests.c,v 2.9 2004/06/02 19:08:52 roberto Exp roberto $ | 2 | ** $Id: ltests.c,v 2.10 2004/07/09 18:23:17 roberto Exp roberto $ |
| 3 | ** Internal Module for Debugging of the Lua Implementation | 3 | ** Internal Module for Debugging of the Lua Implementation |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -153,9 +153,9 @@ void *debug_realloc (void *ud, void *block, size_t oldsize, size_t size) { | |||
| 153 | 153 | ||
| 154 | static int testobjref1 (global_State *g, GCObject *f, GCObject *t) { | 154 | static int testobjref1 (global_State *g, GCObject *f, GCObject *t) { |
| 155 | if (isdead(g,t)) return 0; | 155 | if (isdead(g,t)) return 0; |
| 156 | if (g->gcstate == GCSpropagate) | 156 | if (g->gcstate == GCSpropagate || g->gcgenerational) |
| 157 | return !isblack(f) || !iswhite(t); | 157 | return !isblack(f) || !iswhite(t); |
| 158 | else if (g->gcstate == GCSfinalize) | 158 | else if (g->gcstate == GCSfinalize && !g->gcgenerational) |
| 159 | return iswhite(f); | 159 | return iswhite(f); |
| 160 | else | 160 | else |
| 161 | return 1; | 161 | return 1; |
| @@ -175,7 +175,8 @@ static void printobj (global_State *g, GCObject *o) { | |||
| 175 | static int testobjref (global_State *g, GCObject *f, GCObject *t) { | 175 | static int testobjref (global_State *g, GCObject *f, GCObject *t) { |
| 176 | int r = testobjref1(g,f,t); | 176 | int r = testobjref1(g,f,t); |
| 177 | if (!r) { | 177 | if (!r) { |
| 178 | printf("%d(%02X) - ", g->gcstate, g->currentwhite); | 178 | printf("%d(%02X) %c - ", g->gcstate, g->currentwhite, |
| 179 | g->gcgenerational ? 'G' : ' '); | ||
| 179 | printobj(g, f); | 180 | printobj(g, f); |
| 180 | printf("\t-> "); | 181 | printf("\t-> "); |
| 181 | printobj(g, t); | 182 | printobj(g, t); |
| @@ -290,9 +291,12 @@ static void checkstack (global_State *g, lua_State *L1) { | |||
| 290 | 291 | ||
| 291 | static void checkobject (global_State *g, GCObject *o) { | 292 | static void checkobject (global_State *g, GCObject *o) { |
| 292 | if (isdead(g, o)) | 293 | if (isdead(g, o)) |
| 293 | lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep); | 294 | /* lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep);*/ |
| 295 | { if (!(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep)) | ||
| 296 | printf(">>> %d %s %02x\n", g->gcstate, luaT_typenames[o->gch.tt], o->gch.marked); | ||
| 297 | } | ||
| 294 | else { | 298 | else { |
| 295 | if (g->gcstate == GCSfinalize) | 299 | if (g->gcstate == GCSfinalize && !g->gcgenerational) |
| 296 | lua_assert(iswhite(o)); | 300 | lua_assert(iswhite(o)); |
| 297 | switch (o->gch.tt) { | 301 | switch (o->gch.tt) { |
| 298 | case LUA_TUPVAL: { | 302 | case LUA_TUPVAL: { |
