diff --git a/lgc.c b/lgc.c index 44e5dc31..8d185cd7 100644 --- a/lgc.c +++ b/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.215 2016/12/22 13:08:50 roberto Exp roberto $ +** $Id: lgc.c,v 2.216 2017/02/23 21:07:34 roberto Exp roberto $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -9,7 +9,7 @@ #include "lprefix.h" - +#include #include #include "lua.h" @@ -26,12 +26,6 @@ #include "ltm.h" -/* -** internal state for collector while inside the atomic phase. The -** collector should never be in this state while running regular code. -*/ -#define GCSinsideatomic (GCSpause + 1) - /* ** cost of sweeping one element (the size of a small object divided ** by some adjust for the sweep speed) @@ -59,8 +53,9 @@ #define PAUSEADJ 100 -/* mask to erase all color bits */ -#define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS)) +/* mask to erase all color bits (plus gen. related stuff) */ +#define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS | AGEBITS)) + /* macro to erase all color bits then sets only the current white bit */ #define makewhite(g,x) \ @@ -157,8 +152,10 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); if (keepinvariant(g)) { /* must keep invariant? */ reallymarkobject(g, v); /* restore invariant */ - if (isold(o)) - l_setbit((v)->marked, OLDBIT); + if (isold(o)) { + lua_assert(!isold(v)); + setage(v, G_OLD0); + } } else { /* sweep phase */ lua_assert(issweepphase(g)); @@ -174,8 +171,12 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { void luaC_barrierback_ (lua_State *L, Table *t) { global_State *g = G(L); lua_assert(isblack(t) && !isdead(g, t)); + lua_assert(issweepphase(g) || getage(t) != G_TOUCHED1); + lua_assert(g->gckind != KGC_GEN || isold(t)); + if (getage(t) != G_TOUCHED2) /* not already in gray list? */ + linkgclist(t, g->grayagain); /* link it in 'grayagain' */ black2gray(t); /* make table gray (again) */ - linkgclist(t, g->grayagain); + setage(t, G_TOUCHED1); /* touched in current cycle */ } @@ -188,10 +189,10 @@ void luaC_barrierback_ (lua_State *L, Table *t) { void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) { global_State *g = G(L); GCObject *o = gcvalue(uv->v); - lua_assert(!upisopen(uv)); /* ensured by macro luaC_upvalbarrier */ if (keepinvariant(g)) { markobject(g, o); - l_setbit((o)->marked, OLDBIT); + if (!isold(o)) + setage(o, G_OLD0); } } @@ -379,10 +380,10 @@ static void traverseweakvalue (global_State *g, Table *h) { hasclears = 1; /* table will have to be cleared */ } } - if (g->gcstate == GCSpropagate) - linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ - else if (hasclears) + if (g->gcstate == GCSatomic && hasclears) linkgclist(h, g->weak); /* has to be cleared later */ + else + linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ } @@ -431,6 +432,8 @@ static int traverseephemeron (global_State *g, Table *h) { linkgclist(h, g->ephemeron); /* have to propagate again */ else if (hasclears) /* table has white keys? */ linkgclist(h, g->allweak); /* may have to clean white keys */ + else if (g->gckind == KGC_GEN) + linkgclist(h, g->grayagain); /* keep it in some list */ return marked; } @@ -450,6 +453,10 @@ static void traversestrongtable (global_State *g, Table *h) { markvalue(g, gval(n)); /* mark value */ } } + if (g->gckind == KGC_GEN) { + linkgclist(h, g->grayagain); /* keep it in some gray list */ + black2gray(h); + } } @@ -522,7 +529,7 @@ static lu_mem traverseLclosure (global_State *g, LClosure *cl) { for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */ UpVal *uv = cl->upvals[i]; if (uv != NULL) { - if (upisopen(uv) && g->gcstate != GCSinsideatomic) + if (upisopen(uv) && g->gcstate != GCSatomic) uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */ else markvalue(g, uv->v); @@ -536,11 +543,11 @@ static lu_mem traversethread (global_State *g, lua_State *th) { StkId o = th->stack; if (o == NULL) return 1; /* stack not completely built yet */ - lua_assert(g->gcstate == GCSinsideatomic || + lua_assert(g->gcstate == GCSatomic || th->openupval == NULL || isintwups(th)); for (; o < th->top; o++) /* mark live elements in the stack */ markvalue(g, o); - if (g->gcstate == GCSinsideatomic) { /* final traversal? */ + if (g->gcstate == GCSatomic) { /* final traversal? */ StkId lim = th->stack + th->stacksize; /* real end of stack */ for (; o < lim; o++) /* clear not-marked stack slice */ setnilvalue(o); @@ -564,7 +571,7 @@ static lu_mem traversethread (global_State *g, lua_State *th) { static void propagatemark (global_State *g) { lu_mem size; GCObject *o = g->gray; - lua_assert(isgray(o)); + lua_assert(ongraylist(o)); gray2black(o); switch (o->tt) { case LUA_TTABLE: { @@ -638,11 +645,10 @@ static void convergeephemerons (global_State *g) { /* -** clear entries with unmarked keys from all weaktables in list 'l' up -** to element 'f' +** clear entries with unmarked keys from all weaktables in list 'l' */ -static void clearkeys (global_State *g, GCObject *l, GCObject *f) { - for (; l != f; l = gco2t(l)->gclist) { +static void clearkeys (global_State *g, GCObject *l) { + for (; l; l = gco2t(l)->gclist) { Table *h = gco2t(l); Node *n, *limit = gnodelast(h); for (n = gnode(h, 0); n < limit; n++) { @@ -885,11 +891,13 @@ static void separatetobefnz (global_State *g, int all) { GCObject *curr; GCObject **p = &g->finobj; GCObject **lastnext = findlast(&g->tobefnz); - while ((curr = *p) != NULL) { /* traverse all finalizable objects */ + while ((curr = *p) != g->finobjold) { /* traverse all finalizable objects */ lua_assert(tofinalize(curr)); if (!(iswhite(curr) || all)) /* not being collected? */ p = &curr->next; /* don't bother with it */ else { + if (curr == g->finobjsur) + g->finobjsur = curr->next; *p = curr->next; /* remove 'curr' from 'finobj' list */ curr->next = *lastnext; /* link at the end of 'tobefnz' list */ *lastnext = curr; @@ -915,6 +923,14 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */ } + else { + if (o == g->survival) + g->survival = o->next; + if (o == g->old) + g->old = o->next; + if (o == g->reallyold) + g->reallyold = o->next; + } /* search for pointer pointing to 'o' */ for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } *p = o->next; /* remove 'o' from 'allgc' list */ @@ -934,31 +950,65 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { */ +/* mask to erase all color bits (not changing gen-related stuff) */ +#define maskgencolors (~(bitmask(BLACKBIT) | WHITEBITS)) + #if 0 static int count (GCObject *p, GCObject *limit) { int res = 0; - for (; p != NULL && p != limit; p = p->next) + for (; p != NULL && p != limit; p = p->next) { res++; + } return res; } #endif -static GCObject **sweepgen (lua_State *L, GCObject **p, GCObject *limit, - int zeromask, int onemask) { - global_State *g = G(L); - int ow = otherwhite(g); +static void sweep2old (lua_State *L, GCObject **p) { GCObject *curr; - while ((curr = *p) != limit) { - int marked = curr->marked; - if (isdeadm(ow, marked)) { /* is 'curr' dead? */ - lua_assert(!isold(curr)); + while ((curr = *p) != NULL) { + if (iswhite(curr)) { /* is 'curr' dead? */ + lua_assert(isdead(G(L), curr)); *p = curr->next; /* remove 'curr' from list */ freeobj(L, curr); /* erase 'curr' */ } - else { /* correct mark */ - if (!isold(curr)) /* don't change old objects */ - curr->marked = cast_byte((marked & zeromask) | onemask); + else { /* all surviving objects become old */ + setage(curr, G_OLD); + p = &curr->next; /* go to next element */ + } + } +} + + +static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, + GCObject *limit) { + int white = luaC_white(g); + GCObject *curr; + while ((curr = *p) != limit) { + int marked = curr->marked; + if (iswhite(curr)) { /* is 'curr' dead? */ + lua_assert(!isold(curr) && !testbits(curr->marked, white)); + *p = curr->next; /* remove 'curr' from list */ + freeobj(L, curr); /* erase 'curr' */ + } + else { /* correct mark and age */ + switch (getage(curr)) { + case G_NEW: /* make white and go to next age */ + curr->marked = cast_byte((marked & maskgencolors) | white); + changeage(curr, G_NEW, G_SURVIVAL); + break; + case G_SURVIVAL: /* go to next age */ + changeage(curr, G_SURVIVAL, G_OLD1); + break; + case G_OLD0: /* go to next age */ + changeage(curr, G_OLD0, G_OLD1); + break; + case G_OLD1: /* go to next age */ + changeage(curr, G_OLD1, G_OLD); + break; + default: /* don't change 'old', 'touched1', and 'touched2' */ + break; + } p = &curr->next; /* go to next element */ } } @@ -966,51 +1016,184 @@ static GCObject **sweepgen (lua_State *L, GCObject **p, GCObject *limit, } -static void startgencycle (lua_State *L, global_State *g) { - propagateall(g); - atomic(L); +static void whitelist (global_State *g, GCObject *p) { + int white = luaC_white(g); + for (; p != NULL; p = p->next) + p->marked = cast_byte((p->marked & maskcolors) | white); } -static void finishgencycle (lua_State *L, global_State *g, int mask) { - sweepgen(L, &g->finobj, NULL, ~0, mask); - sweepgen(L, &g->tobefnz, NULL, ~0, mask); +static void finishgencycle (lua_State *L, global_State *g) { + // sweepgen(L, &g->tobefnz, ~0, mask); checkSizes(L, g); g->gcstate = GCSpropagate; /* skip restart */ callallpendingfinalizers(L); } +static void printgray (GCObject *o) { + printf("gray: "); + while (o) { + printf("%p %d %02x ", (void*)o, o->tt, o->marked); + switch (o->tt) { + case LUA_TTABLE: { + Table *h = gco2t(o); + o = h->gclist; + break; + } + case LUA_TLCL: { + LClosure *cl = gco2lcl(o); + o = cl->gclist; + break; + } + case LUA_TCCL: { + CClosure *cl = gco2ccl(o); + o = cl->gclist; + break; + } + case LUA_TTHREAD: { + lua_State *th = gco2th(o); + o = th->gclist; + break; + } + case LUA_TPROTO: { + Proto *p = gco2p(o); + o = p->gclist; + break; + } + default: lua_assert(0); return; + } + } + printf("\n"); +} + + + +static GCObject **correctgraylist (GCObject **p) { + GCObject *curr; + while ((curr = *p) != NULL) { + switch (curr->tt) { + case LUA_TTABLE: { + Table *h = gco2t(curr); + if (getage(h) == G_TOUCHED1) { /* touched in this cycle? */ + lua_assert(isgray(h)); + gray2black(h); /* make it black, for next barrier */ + changeage(h, G_TOUCHED1, G_TOUCHED2); + p = &h->gclist; /* go to next element */ + } + else { + if (!iswhite(h)) { + lua_assert(isold(h)); + if (getage(h) == G_TOUCHED2) + changeage(h, G_TOUCHED2, G_OLD); + gray2black(h); /* make it black */ + } + *p = h->gclist; /* remove 'curr' from gray list */ + } + break; + } + case LUA_TTHREAD: { + lua_State *th = gco2th(curr); + lua_assert(!isblack(th)); + if (iswhite(th)) /* new object? */ + *p = th->gclist; /* remove from gray list */ + else /* old threads remain gray */ + p = &th->gclist; /* go to next element */ + break; + } + default: lua_assert(0); /* nothing more could be gray here */ + } + } + return p; +} + + +static void correctgraylists (global_State *g) { + GCObject **list = correctgraylist(&g->grayagain); + *list = g->weak; g->weak = NULL; + list = correctgraylist(list); + *list = g->allweak; g->allweak = NULL; + list = correctgraylist(list); + *list = g->ephemeron; g->ephemeron = NULL; + correctgraylist(list); +} + + +static void markold (global_State *g, GCObject *from, GCObject *to) { + GCObject *p; + for (p = from; p != to; p = p->next) { + if (getage(p) == G_OLD1) { + lua_assert(!iswhite(p)); + if (isblack(p)) { + black2gray(p); /* should be '2white', but gray works too */ + reallymarkobject(g, p); + } + else + lua_assert(p->tt == LUA_TTHREAD); /* threads are always gray */ + } + } +} + static void youngcollection (lua_State *L, global_State *g) { GCObject **psurvival; lua_assert(g->gcstate == GCSpropagate); - startgencycle(L, g); + markold(g, g->survival, g->reallyold); + markold(g, g->finobj, g->finobjrold); /* ??? */ + atomic(L); + /* sweep nursery */ - psurvival = sweepgen(L, &g->allgc, g->survival, maskcolors, luaC_white(g)); - lua_assert(*psurvival == g->survival); - /* sweep 'survival' list, making elements old */ - sweepgen(L, psurvival, g->old, ~0, bitmask(OLDBIT)); - /* incorporate 'survival' list into old list */ - g->old = *psurvival; - /* surviving young objects go to 'survival' list */ - g->survival = g->allgc; - finishgencycle(L, g, 0); -lua_checkmemory(L); + psurvival = sweepgen(L, g, &g->allgc, g->survival); + /* sweep 'survival' and 'old' */ + sweepgen(L, g, psurvival, g->reallyold); + g->reallyold = g->old; + g->old = *psurvival; /* 'survival' survivals are old now */ + g->survival = g->allgc; /* all news are survivals */ + + /* repeat for 'finobj' lists */ + psurvival = sweepgen(L, g, &g->finobj, g->finobjsur); + /* sweep 'survival' and 'old' */ + sweepgen(L, g, psurvival, g->finobjrold); + g->finobjrold = g->finobjold; + g->finobjold = *psurvival; /* 'survival' survivals are old now */ + g->finobjsur = g->finobj; /* all news are survivals */ + + sweepgen(L, g, &g->tobefnz, NULL); + + finishgencycle(L, g); + correctgraylists(g); +//printf("check: \n");lua_checkmemory(L); } static void entergen (lua_State *L, global_State *g) { -lua_checkmemory(L); - lua_assert(g->old == NULL && g->survival == NULL); + lua_assert(g->reallyold == NULL && g->old == NULL && g->survival == NULL); luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */ luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ - startgencycle(L, g); + atomic(L); /* sweep all ellements making them old */ - sweepgen(L, &g->allgc, g->survival, ~0, bitmask(OLDBIT)); - /* everything alive now is old; 'survival' is empty */ - g->old = g->survival = g->allgc; - finishgencycle(L, g, bitmask(OLDBIT)); -lua_checkmemory(L); + sweep2old(L, &g->allgc); + /* everything alive now is old */ + g->reallyold = g->old = g->survival = g->allgc; + + /* repeat for 'finobj' lists */ + sweep2old(L, &g->finobj); + g->finobjrold = g->finobjold = g->finobjsur = g->finobj; + + finishgencycle(L, g); + correctgraylists(g); + g->gckind = KGC_GEN; +} + + +static void enterinc (global_State *g) { + makewhite(g, g->mainthread); + whitelist(g, g->allgc); + g->reallyold = g->old = g->survival = NULL; + whitelist(g, g->finobj); + g->finobjrold = g->finobjold = g->finobjsur = NULL; + lua_assert(g->tobefnz == NULL); /* no need to sweep */ + g->gcstate = GCSpause; + g->gckind = KGC_NORMAL; } @@ -1019,17 +1202,18 @@ void luaC_changemode (lua_State *L, int newmode) { if (newmode != g->gckind) { /* otherwise, nothing to be done */ if (newmode == KGC_GEN) /* entering generational mode? */ entergen(L, g); - else { /* entering incremental mode */ -lua_checkmemory(L); - youngcollection(L, g); - g->old = g->survival = NULL; -lua_checkmemory(L); - } - g->gckind = newmode; + else + enterinc(g); /* entering incremental mode */ } } +static void fullgen (lua_State *L, global_State *g) { + enterinc(g); + entergen(L, g); +} + + static void genstep (lua_State *L, global_State *g) { lu_mem mem; youngcollection(L, g); @@ -1094,10 +1278,10 @@ static void deletealllist (lua_State *L, GCObject *p) { void luaC_freeallobjects (lua_State *L) { global_State *g = G(L); + luaC_changemode(L, KGC_NORMAL); separatetobefnz(g, 1); /* separate all objects with finalizers */ lua_assert(g->finobj == NULL); callallpendingfinalizers(L); - lua_assert(g->tobefnz == NULL); deletealllist(L, g->finobj); deletealllist(L, g->allgc); deletealllist(L, g->fixedgc); /* collect fixed objects */ @@ -1110,9 +1294,10 @@ static l_mem atomic (lua_State *L) { l_mem work; GCObject *origweak, *origall; GCObject *grayagain = g->grayagain; /* save original list */ + g->grayagain = NULL; lua_assert(g->ephemeron == NULL && g->weak == NULL); lua_assert(!iswhite(g->mainthread)); - g->gcstate = GCSinsideatomic; + g->gcstate = GCSatomic; g->GCmemtrav = 0; /* start counting work */ markobject(g, L); /* mark running thread */ /* registry and global metatables may be changed by API */ @@ -1123,7 +1308,6 @@ static l_mem atomic (lua_State *L) { propagateall(g); /* propagate changes */ work = g->GCmemtrav; /* stop counting (do not recount 'grayagain') */ g->gray = grayagain; - g->grayagain = NULL; propagateall(g); /* traverse 'grayagain' list */ g->GCmemtrav = 0; /* restart counting */ convergeephemerons(g); @@ -1141,13 +1325,14 @@ static l_mem atomic (lua_State *L) { convergeephemerons(g); /* at this point, all resurrected objects are marked. */ /* remove dead objects from weak tables */ - clearkeys(g, g->ephemeron, NULL); /* clear keys from all ephemeron tables */ - clearkeys(g, g->allweak, NULL); /* clear keys from all 'allweak' tables */ + clearkeys(g, g->ephemeron); /* clear keys from all ephemeron tables */ + clearkeys(g, g->allweak); /* clear keys from all 'allweak' tables */ /* clear values from resurrected weak tables */ clearvalues(g, g->weak, origweak); clearvalues(g, g->allweak, origall); luaS_clearcache(g); g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ + lua_assert(g->gray == NULL); work += g->GCmemtrav; /* complete counting */ return work; /* estimate of memory marked by 'atomic' */ } @@ -1181,12 +1366,12 @@ static lu_mem singlestep (lua_State *L) { case GCSpropagate: { g->GCmemtrav = 0; if (g->gray == NULL) /* no more gray objects? */ - g->gcstate = GCSatomic; /* finish propagate phase */ + g->gcstate = GCSenteratomic; /* finish propagate phase */ else propagatemark(g); /* traverse one gray object */ return g->GCmemtrav; /* memory traversed in this step */ } - case GCSatomic: { + case GCSenteratomic: { lu_mem work; propagateall(g); /* make sure gray list is empty */ work = atomic(L); /* work is what was traversed by 'atomic' */ @@ -1291,23 +1476,31 @@ void luaC_step (lua_State *L) { ** to sweep all objects to turn them back to white (as white has not ** changed, nothing will be collected). */ -void luaC_fullgc (lua_State *L, int isemergency) { - global_State *g = G(L); - lua_assert(g->gckind == KGC_NORMAL); - if (isemergency) g->gckind = KGC_EMERGENCY; /* set flag */ - if (keepinvariant(g)) { /* black objects? */ +static void fullinc (lua_State *L, global_State *g) { + if (keepinvariant(g)) /* black objects? */ entersweep(L); /* sweep everything to turn them back to white */ - } /* finish any pending sweep phase to start a new cycle */ luaC_runtilstate(L, bitmask(GCSpause)); luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ /* estimate must be correct after a full GC cycle */ lua_assert(g->GCestimate == gettotalbytes(g)); luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ - g->gckind = KGC_NORMAL; setpause(g); } + +void luaC_fullgc (lua_State *L, int isemergency) { + global_State *g = G(L); + int gckind = g->gckind; + if (isemergency) + g->gckind = KGC_EMERGENCY; /* set flag */ + if (gckind == KGC_NORMAL) + fullinc(L, g); + else + fullgen(L, g); + g->gckind = gckind; +} + /* }====================================================== */ diff --git a/lgc.h b/lgc.h index e75ff85c..158c0e38 100644 --- a/lgc.h +++ b/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.91 2015/12/21 13:02:14 roberto Exp roberto $ +** $Id: lgc.h,v 2.92 2017/02/23 21:07:34 roberto Exp roberto $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -37,13 +37,14 @@ ** Possible states of the Garbage Collector */ #define GCSpropagate 0 -#define GCSatomic 1 -#define GCSswpallgc 2 -#define GCSswpfinobj 3 -#define GCSswptobefnz 4 -#define GCSswpend 5 -#define GCScallfin 6 -#define GCSpause 7 +#define GCSenteratomic 1 +#define GCSatomic 2 +#define GCSswpallgc 3 +#define GCSswpfinobj 4 +#define GCSswptobefnz 5 +#define GCSswpend 6 +#define GCScallfin 7 +#define GCSpause 8 #define issweepphase(g) \ @@ -74,14 +75,17 @@ #define testbit(x,b) testbits(x, bitmask(b)) -/* Layout for bit use in 'marked' field: */ -#define WHITE0BIT 0 /* object is white (type 0) */ -#define WHITE1BIT 1 /* object is white (type 1) */ -#define BLACKBIT 2 /* object is black */ -#define FINALIZEDBIT 3 /* object has been marked for finalization */ -#define OLDBIT 4 /* object is old (gen. mode) */ +/* +** Layout for bit use in 'marked' field. First three bits are +** used for object "age" in generational mode. +*/ +#define WHITE0BIT 3 /* object is white (type 0) */ +#define WHITE1BIT 4 /* object is white (type 1) */ +#define BLACKBIT 5 /* object is black */ +#define FINALIZEDBIT 6 /* object has been marked for finalization */ #define TESTGRAYBIT 7 /* used by tests (luaL_checkmemory) */ + #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) @@ -89,7 +93,6 @@ #define isblack(x) testbit((x)->marked, BLACKBIT) #define isgray(x) /* neither white nor black */ \ (!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT))) -#define isold(x) testbit((x)->marked, OLDBIT) #define tofinalize(x) testbit((x)->marked, FINALIZEDBIT) @@ -103,6 +106,27 @@ #define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) +/* object age in generational mode */ +#define G_NEW 0 /* created in current cycle */ +#define G_SURVIVAL 1 /* created in previous cycle */ +#define G_OLD1 2 /* first full cycle as old */ +#define G_OLD0 3 /* marked old by frw. barrier in this cycle */ +#define G_OLD 4 /* really old object (not to be visited) */ +#define G_TOUCHED1 5 /* old object touched this cycle */ +#define G_TOUCHED2 6 /* old object touched in previous cycle */ + +#define AGEBITS 7 /* all age bits (111) */ + +#define getage(o) ((o)->marked & AGEBITS) +#define setage(o,a) ((o)->marked = cast_byte(((o)->marked & (~AGEBITS)) | a)) +#define isold(o) (getage(o) > G_SURVIVAL) + +#define changeage(o,f,t) \ + check_exp(getage(o) == (f), (o)->marked ^= ((f)^(t))) + +#define ongraylist(o) (isgray(o) || getage(o) == G_TOUCHED2) + + /* ** Does one step of collection when debt becomes positive. 'pre'/'pos' ** allows some adjustments to be done only when needed. macro diff --git a/lstate.c b/lstate.c index 4900d724..d2f38588 100644 --- a/lstate.c +++ b/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.133 2015/11/13 12:16:51 roberto Exp roberto $ +** $Id: lstate.c,v 2.134 2017/02/23 21:07:34 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -319,7 +319,8 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->gcstate = GCSpause; g->gckind = KGC_NORMAL; g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL; - g->survival = g->old = NULL; + g->survival = g->old = g->reallyold = NULL; + g->finobjsur = g->finobjold = g->finobjrold = NULL; g->sweepgc = NULL; g->gray = g->grayagain = NULL; g->weak = g->ephemeron = g->allweak = NULL; diff --git a/lstate.h b/lstate.h index 51128db1..b01859aa 100644 --- a/lstate.h +++ b/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.134 2017/02/15 18:52:13 roberto Exp roberto $ +** $Id: lstate.h,v 2.135 2017/02/23 21:07:34 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ @@ -160,8 +160,12 @@ typedef struct global_State { GCObject *tobefnz; /* list of userdata to be GC */ GCObject *fixedgc; /* list of objects not to be collected */ /* fields for generational collector */ - GCObject *old; /* start of old objects */ GCObject *survival; /* start of objects that survived one GC cycle */ + GCObject *old; /* start of old objects */ + GCObject *reallyold; /* old objects with more than one cycle */ + GCObject *finobjsur; /* list of survival objects with finalizers */ + GCObject *finobjold; /* list of old objects with finalizers */ + GCObject *finobjrold; /* list of really old objects with finalizers */ struct lua_State *twups; /* list of threads with open upvalues */ unsigned int gcfinnum; /* number of finalizers to call in each GC step */ int gcpause; /* size of pause between successive GCs */