diff options
-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: { |