generational collector (still not complete)

This commit is contained in:
Roberto Ierusalimschy 2017-04-05 13:50:51 -03:00
parent 1a1b2f3d7f
commit e4287da3a6
4 changed files with 326 additions and 104 deletions

363
lgc.c
View File

@ -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 <stdio.h>
#include <string.h>
#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;
}
/* }====================================================== */

54
lgc.h
View File

@ -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

View File

@ -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;

View File

@ -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 */