diff options
Diffstat (limited to 'lgc.c')
-rw-r--r-- | lgc.c | 75 |
1 files changed, 44 insertions, 31 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 1.185 2003/12/04 17:22:42 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 1.186 2003/12/04 18:52: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,12 +25,8 @@ | |||
25 | #define GCSTEPSIZE (20*sizeof(TObject)) | 25 | #define GCSTEPSIZE (20*sizeof(TObject)) |
26 | 26 | ||
27 | 27 | ||
28 | #define otherwhite(g) (g->currentwhite ^ bit2mask(WHITE0BIT, WHITE1BIT)) | ||
29 | |||
30 | #define isblack(x) testbit((x)->gch.marked, BLACKBIT) | ||
31 | #define gray2black(x) setbit((x)->gch.marked, BLACKBIT) | 28 | #define gray2black(x) setbit((x)->gch.marked, BLACKBIT) |
32 | 29 | ||
33 | #define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) | ||
34 | #define maskmarks \ | 30 | #define maskmarks \ |
35 | cast(lu_byte, ~(bitmask(BLACKBIT)|bit2mask(WHITE0BIT, WHITE1BIT))) | 31 | cast(lu_byte, ~(bitmask(BLACKBIT)|bit2mask(WHITE0BIT, WHITE1BIT))) |
36 | #define makewhite(g,x) \ | 32 | #define makewhite(g,x) \ |
@@ -47,7 +43,6 @@ | |||
47 | #define markfinalized(u) setbit((u)->uv.marked, FINALIZEDBIT) | 43 | #define markfinalized(u) setbit((u)->uv.marked, FINALIZEDBIT) |
48 | 44 | ||
49 | 45 | ||
50 | |||
51 | #define KEYWEAK bitmask(KEYWEAKBIT) | 46 | #define KEYWEAK bitmask(KEYWEAKBIT) |
52 | #define VALUEWEAK bitmask(VALUEWEAKBIT) | 47 | #define VALUEWEAK bitmask(VALUEWEAKBIT) |
53 | 48 | ||
@@ -110,7 +105,7 @@ static size_t objsize (GCObject *o) { | |||
110 | 105 | ||
111 | static void reallymarkobject (global_State *g, GCObject *o) { | 106 | static void reallymarkobject (global_State *g, GCObject *o) { |
112 | lua_assert(iswhite(o)); | 107 | lua_assert(iswhite(o)); |
113 | lua_assert(!(o->gch.marked & otherwhite(g))); | 108 | lua_assert(!isdead(g, o)); |
114 | white2gray(o); | 109 | white2gray(o); |
115 | switch (o->gch.tt) { | 110 | switch (o->gch.tt) { |
116 | case LUA_TSTRING: { | 111 | case LUA_TSTRING: { |
@@ -118,6 +113,7 @@ static void reallymarkobject (global_State *g, GCObject *o) { | |||
118 | } | 113 | } |
119 | case LUA_TUSERDATA: { | 114 | case LUA_TUSERDATA: { |
120 | Table *mt = gcotou(o)->uv.metatable; | 115 | Table *mt = gcotou(o)->uv.metatable; |
116 | gray2black(o); /* udata are never gray */ | ||
121 | if (mt) markobject(g, mt); | 117 | if (mt) markobject(g, mt); |
122 | return; | 118 | return; |
123 | } | 119 | } |
@@ -442,7 +438,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int all, | |||
442 | int dead = otherwhite(g); | 438 | int dead = otherwhite(g); |
443 | while ((curr = *p) != NULL) { | 439 | while ((curr = *p) != NULL) { |
444 | int mark = curr->gch.marked; | 440 | int mark = curr->gch.marked; |
445 | lua_assert(all || !(mark & g->currentwhite)); | ||
446 | lim -= objsize(curr); | 441 | lim -= objsize(curr); |
447 | if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) { | 442 | if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) { |
448 | makewhite(g, curr); | 443 | makewhite(g, curr); |
@@ -469,9 +464,9 @@ static l_mem sweepstrings (lua_State *L, int all, l_mem lim) { | |||
469 | while ((curr = *p) != NULL) { | 464 | while ((curr = *p) != NULL) { |
470 | int mark = curr->gch.marked; | 465 | int mark = curr->gch.marked; |
471 | lu_mem size = sizestring(gcotots(curr)->tsv.len); | 466 | lu_mem size = sizestring(gcotots(curr)->tsv.len); |
472 | lua_assert(all || !(mark & g->currentwhite)); | ||
473 | if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) { | 467 | if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) { |
474 | makewhite(g, curr); | 468 | makewhite(g, curr); |
469 | lua_assert(iswhite(curr) && !isdead(g, curr)); | ||
475 | p = &curr->gch.next; | 470 | p = &curr->gch.next; |
476 | } | 471 | } |
477 | else { | 472 | else { |
@@ -499,8 +494,6 @@ static void checkSizes (lua_State *L) { | |||
499 | size_t newsize = luaZ_sizebuffer(&g->buff) / 2; | 494 | size_t newsize = luaZ_sizebuffer(&g->buff) / 2; |
500 | luaZ_resizebuffer(L, &g->buff, newsize); | 495 | luaZ_resizebuffer(L, &g->buff, newsize); |
501 | } | 496 | } |
502 | lua_assert(g->nblocks > g->GCthreshold); | ||
503 | g->GCthreshold = 2*G(L)->nblocks - g->GCthreshold; /* new threshold */ | ||
504 | } | 497 | } |
505 | 498 | ||
506 | 499 | ||
@@ -562,11 +555,13 @@ static void markroot (lua_State *L) { | |||
562 | 555 | ||
563 | static void atomic (lua_State *L) { | 556 | static void atomic (lua_State *L) { |
564 | global_State *g = G(L); | 557 | global_State *g = G(L); |
558 | /* there may be some gray elements due to the write barrier */ | ||
559 | propagatemarks(g, MAXLMEM); /* traverse them */ | ||
565 | lua_assert(g->gray == NULL); | 560 | lua_assert(g->gray == NULL); |
566 | g->gray = g->grayagain; | 561 | g->gray = g->grayagain; |
567 | g->grayagain = NULL; | 562 | g->grayagain = NULL; |
568 | propagatemarks(g, MAXLMEM); | 563 | propagatemarks(g, MAXLMEM); |
569 | g->GCthreshold = luaC_separateudata(L); /* separate userdata to be preserved */ | 564 | luaC_separateudata(L); /* separate userdata to be preserved */ |
570 | marktmu(g); /* mark `preserved' userdata */ | 565 | marktmu(g); /* mark `preserved' userdata */ |
571 | propagatemarks(g, MAXLMEM); /* remark, to propagate `preserveness' */ | 566 | propagatemarks(g, MAXLMEM); /* remark, to propagate `preserveness' */ |
572 | cleartable(g->weak); /* remove collected objects from weak tables */ | 567 | cleartable(g->weak); /* remove collected objects from weak tables */ |
@@ -597,30 +592,48 @@ static void sweepstep (lua_State *L) { | |||
597 | global_State *g = G(L); | 592 | global_State *g = G(L); |
598 | l_mem lim = GCSTEPSIZE; | 593 | l_mem lim = GCSTEPSIZE; |
599 | g->sweepgc = sweeplist(L, g->sweepgc, 0, &lim); | 594 | g->sweepgc = sweeplist(L, g->sweepgc, 0, &lim); |
600 | if (lim == GCSTEPSIZE) /* nothing more to sweep? */ | 595 | if (lim == GCSTEPSIZE) { /* nothing more to sweep? */ |
601 | g->gcstate = GCSfinalize; /* end sweep phase */ | 596 | g->gcstate = GCSfinalize; /* end sweep phase */ |
597 | checkSizes(L); | ||
598 | } | ||
602 | } | 599 | } |
603 | 600 | ||
604 | 601 | ||
605 | void luaC_collectgarbage (lua_State *L) { | 602 | void luaC_step (lua_State *L) { |
606 | global_State *g = G(L); | 603 | global_State *g = G(L); |
607 | /* GCSroot */ | 604 | switch (g->gcstate) { |
608 | markroot(L); | 605 | case GCSroot: |
609 | /* GCSpropagate */ | 606 | markroot(L); |
610 | while (g->gcstate == GCSpropagate) | 607 | break; |
611 | propagatemarks(g, GCSTEPSIZE); | 608 | case GCSpropagate: |
612 | /* atomic */ | 609 | propagatemarks(g, GCSTEPSIZE); |
613 | atomic(L); | 610 | break; |
614 | /* GCSsweepstring */ | 611 | case GCSatomic: |
615 | while (g->gcstate == GCSsweepstring) | 612 | atomic(L); |
616 | sweepstringstep(L); | 613 | break; |
617 | /* GCSsweep */ | 614 | case GCSsweepstring: |
618 | while (g->gcstate == GCSsweep) | 615 | sweepstringstep(L); |
619 | sweepstep(L); | 616 | break; |
620 | /* GCSfinalize */ | 617 | case GCSsweep: |
621 | checkSizes(L); | 618 | sweepstep(L); |
622 | while (g->gcstate == GCSfinalize) | 619 | break; |
623 | GCTM(L); | 620 | case GCSfinalize: |
621 | GCTM(L); | ||
622 | break; | ||
623 | default: lua_assert(0); | ||
624 | } | ||
625 | g->GCthreshold = g->nblocks + GCSTEPSIZE; | ||
626 | } | ||
627 | |||
628 | |||
629 | void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { | ||
630 | global_State *g = G(L); | ||
631 | lua_assert(isblack(o) && iswhite(v)); | ||
632 | lua_assert(!isdead(g, v) && !isdead(g, o)); | ||
633 | if (g->gcstate > GCSatomic) /* sweeping phases? */ | ||
634 | black2gray(o); /* just mark as gray to avoid other barriers */ | ||
635 | else /* breaking invariant! */ | ||
636 | reallymarkobject(g, v); /* restore it */ | ||
624 | } | 637 | } |
625 | 638 | ||
626 | 639 | ||