mirror of
https://github.com/lua/lua.git
synced 2025-01-28 06:03:00 +08:00
first implementation of generational GC
This commit is contained in:
parent
4b12eff801
commit
32d4f304db
257
lgc.c
257
lgc.c
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lgc.c,v 2.7 2004/04/30 20:13:38 roberto Exp roberto $
|
** $Id: lgc.c,v 2.8 2004/08/10 19:17:23 roberto Exp roberto $
|
||||||
** Garbage Collector
|
** Garbage Collector
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@ -25,10 +25,11 @@
|
|||||||
|
|
||||||
#define GCSTEPSIZE (40*sizeof(TValue))
|
#define GCSTEPSIZE (40*sizeof(TValue))
|
||||||
#define STEPMUL 2
|
#define STEPMUL 2
|
||||||
#define GCFREECOST (sizeof(TValue)/10)
|
#define GCSWEEPMAX 40
|
||||||
#define GCSWEEPCOST (sizeof(TValue)/20)
|
#define GCSWEEPCOST 1
|
||||||
#define GCFINALIZECOST (10*sizeof(TValue))
|
#define GCFINALIZECOST (10*sizeof(TValue))
|
||||||
#define WAITNEXTCYCLE (10 * GCSTEPSIZE)
|
#define WAITNEXTCYCLE (40 * GCSTEPSIZE)
|
||||||
|
#define WAITNEXTCYCLEGN (200 * GCSTEPSIZE)
|
||||||
|
|
||||||
|
|
||||||
#define FIXEDMASK bitmask(FIXEDBIT)
|
#define FIXEDMASK bitmask(FIXEDBIT)
|
||||||
@ -269,60 +270,61 @@ static void traversestack (global_State *g, lua_State *l) {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** traverse a given `quantity' of gray objects,
|
** traverse one gray object, turning it to black.
|
||||||
** turning them to black. Returns extra `quantity' traversed.
|
** Returns `quantity' traversed.
|
||||||
*/
|
*/
|
||||||
static l_mem propagatemarks (global_State *g, l_mem lim) {
|
static l_mem propagatemark (global_State *g) {
|
||||||
GCObject *o;
|
GCObject *o = g->gray;
|
||||||
while ((o = g->gray) != NULL) {
|
lua_assert(isgray(o));
|
||||||
lua_assert(isgray(o));
|
gray2black(o);
|
||||||
gray2black(o);
|
switch (o->gch.tt) {
|
||||||
switch (o->gch.tt) {
|
case LUA_TTABLE: {
|
||||||
case LUA_TTABLE: {
|
Table *h = gco2h(o);
|
||||||
Table *h = gco2h(o);
|
g->gray = h->gclist;
|
||||||
g->gray = h->gclist;
|
if (traversetable(g, h)) /* table is weak? */
|
||||||
if (traversetable(g, h)) /* table is weak? */
|
black2gray(o); /* keep it gray */
|
||||||
black2gray(o); /* keep it gray */
|
return sizeof(Table) + sizeof(TValue) * h->sizearray +
|
||||||
lim -= sizeof(Table) + sizeof(TValue) * h->sizearray +
|
sizeof(Node) * sizenode(h);
|
||||||
sizeof(Node) * sizenode(h);
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
case LUA_TFUNCTION: {
|
|
||||||
Closure *cl = gco2cl(o);
|
|
||||||
g->gray = cl->c.gclist;
|
|
||||||
traverseclosure(g, cl);
|
|
||||||
lim -= (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) :
|
|
||||||
sizeLclosure(cl->l.nupvalues);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case LUA_TTHREAD: {
|
|
||||||
lua_State *th = gco2th(o);
|
|
||||||
g->gray = th->gclist;
|
|
||||||
th->gclist = g->grayagain;
|
|
||||||
g->grayagain = o;
|
|
||||||
black2gray(o);
|
|
||||||
traversestack(g, th);
|
|
||||||
lim -= sizeof(lua_State) + sizeof(TValue) * th->stacksize +
|
|
||||||
sizeof(CallInfo) * th->size_ci;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case LUA_TPROTO: {
|
|
||||||
Proto *p = gco2p(o);
|
|
||||||
g->gray = p->gclist;
|
|
||||||
traverseproto(g, p);
|
|
||||||
lim -= sizeof(Proto) + sizeof(Instruction) * p->sizecode +
|
|
||||||
sizeof(Proto *) * p->sizep +
|
|
||||||
sizeof(TValue) * p->sizek +
|
|
||||||
sizeof(int) * p->sizelineinfo +
|
|
||||||
sizeof(LocVar) * p->sizelocvars +
|
|
||||||
sizeof(TString *) * p->sizeupvalues;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: lua_assert(0);
|
|
||||||
}
|
}
|
||||||
if (lim <= 0) return lim;
|
case LUA_TFUNCTION: {
|
||||||
|
Closure *cl = gco2cl(o);
|
||||||
|
g->gray = cl->c.gclist;
|
||||||
|
traverseclosure(g, cl);
|
||||||
|
return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) :
|
||||||
|
sizeLclosure(cl->l.nupvalues);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LUA_TTHREAD: {
|
||||||
|
lua_State *th = gco2th(o);
|
||||||
|
g->gray = th->gclist;
|
||||||
|
th->gclist = g->grayagain;
|
||||||
|
g->grayagain = o;
|
||||||
|
black2gray(o);
|
||||||
|
traversestack(g, th);
|
||||||
|
return sizeof(lua_State) + sizeof(TValue) * th->stacksize +
|
||||||
|
sizeof(CallInfo) * th->size_ci;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LUA_TPROTO: {
|
||||||
|
Proto *p = gco2p(o);
|
||||||
|
g->gray = p->gclist;
|
||||||
|
traverseproto(g, p);
|
||||||
|
return sizeof(Proto) + sizeof(Instruction) * p->sizecode +
|
||||||
|
sizeof(Proto *) * p->sizep +
|
||||||
|
sizeof(TValue) * p->sizek +
|
||||||
|
sizeof(int) * p->sizelineinfo +
|
||||||
|
sizeof(LocVar) * p->sizelocvars +
|
||||||
|
sizeof(TString *) * p->sizeupvalues;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: lua_assert(0); return 0;
|
||||||
}
|
}
|
||||||
return lim;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void propagateall (global_State *g) {
|
||||||
|
while (g->gray) propagatemark(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -384,6 +386,7 @@ static void freeobj (lua_State *L, GCObject *o) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LUA_TSTRING: {
|
case LUA_TSTRING: {
|
||||||
|
G(L)->strt.nuse--;
|
||||||
luaM_free(L, o, sizestring(gco2ts(o)->len));
|
luaM_free(L, o, sizestring(gco2ts(o)->len));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -396,59 +399,50 @@ static void freeobj (lua_State *L, GCObject *o) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static l_mem sweepwholelist (lua_State *L, GCObject **p, int keepfixed,
|
|
||||||
lu_int32 *count);
|
#define sweepwholelist(L,p) sweeplist(L,p,LUA_MAXINT32)
|
||||||
|
|
||||||
|
|
||||||
static GCObject **sweeplist (lua_State *L, GCObject **p, int keepfixed,
|
static GCObject **sweeplist (lua_State *L, GCObject **p, lu_int32 count) {
|
||||||
l_mem *plim, lu_int32 *count) {
|
|
||||||
GCObject *curr;
|
GCObject *curr;
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
l_mem lim = *plim;
|
int whitebit = otherwhite(g);
|
||||||
int deadmask = otherwhite(g);
|
int deadmask = whitebit | FIXEDMASK;
|
||||||
if (keepfixed) deadmask |= FIXEDMASK;
|
|
||||||
while ((curr = *p) != NULL) {
|
while ((curr = *p) != NULL) {
|
||||||
if (((curr->gch.marked ^ FIXEDMASK) & deadmask) != deadmask) {
|
if ((curr->gch.marked ^ whitebit) & deadmask) {
|
||||||
makewhite(g, curr);
|
lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT));
|
||||||
|
if (!G(L)->gcgenerational || isdead(g, curr))
|
||||||
|
makewhite(g, curr);
|
||||||
if (curr->gch.tt == LUA_TTHREAD)
|
if (curr->gch.tt == LUA_TTHREAD)
|
||||||
lim -= sweepwholelist(L, &gco2th(curr)->openupval, keepfixed, count);
|
sweepwholelist(L, &gco2th(curr)->openupval);
|
||||||
p = &curr->gch.next;
|
p = &curr->gch.next;
|
||||||
lim -= GCSWEEPCOST;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lua_assert(iswhite(curr));
|
lua_assert(isdead(g, curr));
|
||||||
*p = curr->gch.next;
|
*p = curr->gch.next;
|
||||||
if (curr == g->rootgc) /* is the first element of the list? */
|
if (curr == g->rootgc) /* is the first element of the list? */
|
||||||
g->rootgc = curr->gch.next; /* adjust first */
|
g->rootgc = curr->gch.next; /* adjust first */
|
||||||
freeobj(L, curr);
|
freeobj(L, curr);
|
||||||
lim -= GCFREECOST;
|
|
||||||
if (count) (*count)--;
|
|
||||||
}
|
}
|
||||||
if (lim <= 0) break;
|
if (count-- == 0) break;
|
||||||
}
|
}
|
||||||
*plim = lim;
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static l_mem sweepwholelist (lua_State *L, GCObject **p, int keepfixed,
|
static void sweepstrings (lua_State *L) {
|
||||||
lu_int32 *count) {
|
global_State *g = G(L);
|
||||||
l_mem lim = MAXLMEM;
|
sweepwholelist(L, &G(L)->strt.hash[g->sweepstrgc++]);
|
||||||
/* empty lists are quite common here, so avoid useless calls */
|
|
||||||
if (*p) sweeplist(L, p, keepfixed, &lim, count);
|
|
||||||
return MAXLMEM - lim;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static l_mem sweepstrings (lua_State *L, int keepfixed, l_mem lim) {
|
static void freelist (lua_State *L, GCObject **p) {
|
||||||
int i;
|
while (*p) {
|
||||||
global_State *g = G(L);
|
GCObject *curr = *p;
|
||||||
for (i = g->sweepstrgc; i < g->strt.size; i++) { /* for each list */
|
*p = (*p)->gch.next;
|
||||||
lim -= sweepwholelist(L, &G(L)->strt.hash[i], keepfixed, &g->strt.nuse);
|
if (curr != obj2gco(L))
|
||||||
if (lim <= 0) break;
|
freeobj(L, curr);
|
||||||
}
|
}
|
||||||
g->sweepstrgc = i+1;
|
|
||||||
return lim;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -497,19 +491,12 @@ void luaC_callGCTM (lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaC_sweepall (lua_State *L) {
|
void luaC_freeall (lua_State *L) {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
l_mem dummy = MAXLMEM;
|
int i;
|
||||||
/* finish (occasional) current sweep */
|
freelist(L, &g->rootgc);
|
||||||
sweepstrings(L, 0, MAXLMEM);
|
for (i = 0; i < g->strt.size; i++) /* free all string lists */
|
||||||
sweeplist(L, &g->rootgc, 0, &dummy, NULL);
|
freelist(L, &G(L)->strt.hash[i]);
|
||||||
/* do a whole new sweep */
|
|
||||||
markobject(g, g->mainthread); /* cannot collect main thread */
|
|
||||||
g->currentwhite = otherwhite(g);
|
|
||||||
g->sweepgc = &g->rootgc;
|
|
||||||
g->sweepstrgc = 0;
|
|
||||||
sweepstrings(L, 0, MAXLMEM);
|
|
||||||
sweeplist(L, &g->rootgc, 0, &dummy, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -553,64 +540,68 @@ static void atomic (lua_State *L) {
|
|||||||
g->weak = NULL;
|
g->weak = NULL;
|
||||||
lua_assert(!iswhite(obj2gco(g->mainthread)));
|
lua_assert(!iswhite(obj2gco(g->mainthread)));
|
||||||
markobject(g, L); /* mark running thread */
|
markobject(g, L); /* mark running thread */
|
||||||
propagatemarks(g, MAXLMEM);
|
propagateall(g);
|
||||||
/* remark gray again */
|
/* remark gray again */
|
||||||
g->gray = g->grayagain;
|
g->gray = g->grayagain;
|
||||||
g->grayagain = NULL;
|
g->grayagain = NULL;
|
||||||
propagatemarks(g, MAXLMEM);
|
propagateall(g);
|
||||||
luaC_separateudata(L, 0); /* separate userdata to be preserved */
|
luaC_separateudata(L, 0); /* separate userdata to be preserved */
|
||||||
marktmu(g); /* mark `preserved' userdata */
|
marktmu(g); /* mark `preserved' userdata */
|
||||||
propagatemarks(g, MAXLMEM); /* remark, to propagate `preserveness' */
|
propagateall(g); /* remark, to propagate `preserveness' */
|
||||||
cleartable(g->weak); /* remove collected objects from weak tables */
|
cleartable(g->weak); /* remove collected objects from weak tables */
|
||||||
/* flip current white */
|
/* flip current white */
|
||||||
g->currentwhite = otherwhite(g);
|
g->currentwhite = otherwhite(g);
|
||||||
|
g->sweepstrgc = 0;
|
||||||
|
g->sweepgc = &g->rootgc;
|
||||||
g->gcstate = GCSsweepstring;
|
g->gcstate = GCSsweepstring;
|
||||||
|
if (g->gcgenerational++ > 20) g->gcgenerational = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static l_mem singlestep (lua_State *L, l_mem lim) {
|
static l_mem singlestep (lua_State *L) {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
|
/*lua_checkmemory(L);*/
|
||||||
switch (g->gcstate) {
|
switch (g->gcstate) {
|
||||||
case GCSpropagate: {
|
case GCSpropagate: {
|
||||||
if (g->gray)
|
if (g->gray)
|
||||||
lim = propagatemarks(g, lim);
|
return propagatemark(g);
|
||||||
else { /* no more `gray' objects */
|
else { /* no more `gray' objects */
|
||||||
atomic(L); /* finish mark phase */
|
atomic(L); /* finish mark phase */
|
||||||
lim = 0;
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case GCSsweepstring: {
|
case GCSsweepstring: {
|
||||||
lim = sweepstrings(L, 1, lim);
|
sweepstrings(L);
|
||||||
if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */
|
if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */
|
||||||
g->sweepstrgc = 0;
|
|
||||||
g->gcstate = GCSsweep; /* end sweep-string phase */
|
g->gcstate = GCSsweep; /* end sweep-string phase */
|
||||||
}
|
return GCSWEEPCOST;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case GCSsweep: {
|
case GCSsweep: {
|
||||||
g->sweepgc = sweeplist(L, g->sweepgc, 1, &lim, NULL);
|
g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
|
||||||
if (*g->sweepgc == NULL) { /* nothing more to sweep? */
|
if (*g->sweepgc == NULL) { /* nothing more to sweep? */
|
||||||
checkSizes(L);
|
checkSizes(L);
|
||||||
g->sweepgc = &g->rootgc;
|
|
||||||
g->gcstate = GCSfinalize; /* end sweep phase */
|
g->gcstate = GCSfinalize; /* end sweep phase */
|
||||||
}
|
}
|
||||||
break;
|
return GCSWEEPCOST;
|
||||||
}
|
}
|
||||||
case GCSfinalize: {
|
case GCSfinalize: {
|
||||||
if (g->tmudata) {
|
if (g->tmudata) {
|
||||||
GCTM(L);
|
GCTM(L);
|
||||||
lim -= GCFINALIZECOST;
|
return GCFINALIZECOST;
|
||||||
}
|
}
|
||||||
else { /* no more `udata' to finalize */
|
else { /* no more `udata' to finalize */
|
||||||
markroot(L); /* may restart collection */
|
if (g->gcgenerational) {
|
||||||
lim = 0;
|
atomic(L);
|
||||||
|
return WAITNEXTCYCLEGN;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
markroot(L); /* may restart collection */
|
||||||
|
return WAITNEXTCYCLE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
default: lua_assert(0);
|
default: lua_assert(0); return 0;
|
||||||
}
|
}
|
||||||
return lim;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -618,11 +609,7 @@ void luaC_step (lua_State *L) {
|
|||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * STEPMUL;
|
l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * STEPMUL;
|
||||||
do {
|
do {
|
||||||
lim = singlestep(L, lim);
|
lim -= singlestep(L);
|
||||||
if (g->gcstate == GCSfinalize && g->tmudata == NULL) {
|
|
||||||
lim = -WAITNEXTCYCLE;
|
|
||||||
break; /* do not start new collection */
|
|
||||||
}
|
|
||||||
} while (lim > 0);
|
} while (lim > 0);
|
||||||
g->GCthreshold = g->nblocks + GCSTEPSIZE - lim/STEPMUL;
|
g->GCthreshold = g->nblocks + GCSTEPSIZE - lim/STEPMUL;
|
||||||
lua_assert((long)g->nblocks + (long)GCSTEPSIZE >= lim/STEPMUL);
|
lua_assert((long)g->nblocks + (long)GCSTEPSIZE >= lim/STEPMUL);
|
||||||
@ -631,12 +618,26 @@ void luaC_step (lua_State *L) {
|
|||||||
|
|
||||||
void luaC_fullgc (lua_State *L) {
|
void luaC_fullgc (lua_State *L) {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
|
if (g->gcstate == GCSpropagate || g->gcgenerational) {
|
||||||
|
g->gcgenerational = 0;
|
||||||
|
/* reset sweep marks to sweep all elements (returning them to white) */
|
||||||
|
g->sweepstrgc = 0;
|
||||||
|
g->sweepgc = &g->rootgc;
|
||||||
|
/* reset other collector lists */
|
||||||
|
g->gray = NULL;
|
||||||
|
g->grayagain = NULL;
|
||||||
|
g->weak = NULL;
|
||||||
|
g->gcstate = GCSsweepstring;
|
||||||
|
}
|
||||||
|
/* finish any pending sweep phase */
|
||||||
while (g->gcstate != GCSfinalize) {
|
while (g->gcstate != GCSfinalize) {
|
||||||
singlestep(L, MAXLMEM);
|
singlestep(L);
|
||||||
}
|
}
|
||||||
markroot(L);
|
markroot(L);
|
||||||
|
lua_assert(!g->gcgenerational);
|
||||||
while (g->gcstate != GCSfinalize) {
|
while (g->gcstate != GCSfinalize) {
|
||||||
singlestep(L, MAXLMEM);
|
singlestep(L);
|
||||||
|
g->gcgenerational = 0; /* keep it in this mode */
|
||||||
}
|
}
|
||||||
g->GCthreshold = g->nblocks + GCSTEPSIZE;
|
g->GCthreshold = g->nblocks + GCSTEPSIZE;
|
||||||
luaC_callGCTM(L); /* call finalizers */
|
luaC_callGCTM(L); /* call finalizers */
|
||||||
@ -646,7 +647,7 @@ void luaC_fullgc (lua_State *L) {
|
|||||||
void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
|
void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
|
lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
|
||||||
lua_assert(g->gcstate != GCSfinalize);
|
lua_assert(g->gcgenerational || g->gcstate != GCSfinalize);
|
||||||
if (g->gcstate != GCSpropagate) /* sweeping phases? */
|
if (g->gcstate != GCSpropagate) /* sweeping phases? */
|
||||||
black2gray(o); /* just mark as gray to avoid other barriers */
|
black2gray(o); /* just mark as gray to avoid other barriers */
|
||||||
else /* breaking invariant! */
|
else /* breaking invariant! */
|
||||||
@ -657,7 +658,7 @@ void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
|
|||||||
void luaC_barrierback (lua_State *L, GCObject *o, GCObject *v) {
|
void luaC_barrierback (lua_State *L, GCObject *o, GCObject *v) {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
|
lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
|
||||||
lua_assert(g->gcstate != GCSfinalize);
|
lua_assert(g->gcgenerational || g->gcstate != GCSfinalize);
|
||||||
black2gray(o); /* make table gray (again) */
|
black2gray(o); /* make table gray (again) */
|
||||||
gco2h(o)->gclist = g->grayagain;
|
gco2h(o)->gclist = g->grayagain;
|
||||||
g->grayagain = o;
|
g->grayagain = o;
|
||||||
@ -679,7 +680,7 @@ void luaC_linkupval (lua_State *L, UpVal *uv) {
|
|||||||
o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */
|
o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */
|
||||||
g->rootgc = o;
|
g->rootgc = o;
|
||||||
if (isgray(o)) {
|
if (isgray(o)) {
|
||||||
if (g->gcstate == GCSpropagate) {
|
if (g->gcstate == GCSpropagate || g->gcgenerational) {
|
||||||
gray2black(o); /* closed upvalues need barrier */
|
gray2black(o); /* closed upvalues need barrier */
|
||||||
luaC_barrier(L, uv, uv->v);
|
luaC_barrier(L, uv, uv->v);
|
||||||
}
|
}
|
||||||
|
17
lgc.h
17
lgc.h
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lgc.h,v 2.5 2004/03/15 21:04:33 roberto Exp roberto $
|
** $Id: lgc.h,v 2.6 2004/08/10 19:17:23 roberto Exp roberto $
|
||||||
** Garbage Collector
|
** Garbage Collector
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@ -39,12 +39,13 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Layout for bit use in `marked' field:
|
** Layout for bit use in `marked' field:
|
||||||
** bit 0 - object is gray
|
** bit 0 - object is white (type 0)
|
||||||
** bit 1 - object is black
|
** bit 1 - object is white (type 1)
|
||||||
** bit 2 - For userdata: is finalized;
|
** bit 2 - object is black
|
||||||
for tables: has weak keys
|
** bit 3 - for userdata: has been finalized
|
||||||
** bit 3 - for tables: has weak values
|
** bit 3 - for tables: has weak keys
|
||||||
** bit 4 - object is fixed (should not be collected)
|
** bit 4 - for tables: has weak values
|
||||||
|
** bit 5 - object is fixed (should not be collected)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define WHITE0BIT 0
|
#define WHITE0BIT 0
|
||||||
@ -86,7 +87,7 @@
|
|||||||
|
|
||||||
size_t luaC_separateudata (lua_State *L, int all);
|
size_t luaC_separateudata (lua_State *L, int all);
|
||||||
void luaC_callGCTM (lua_State *L);
|
void luaC_callGCTM (lua_State *L);
|
||||||
void luaC_sweepall (lua_State *L);
|
void luaC_freeall (lua_State *L);
|
||||||
void luaC_step (lua_State *L);
|
void luaC_step (lua_State *L);
|
||||||
void luaC_fullgc (lua_State *L);
|
void luaC_fullgc (lua_State *L);
|
||||||
void luaC_link (lua_State *L, GCObject *o, lu_byte tt);
|
void luaC_link (lua_State *L, GCObject *o, lu_byte tt);
|
||||||
|
10
lstate.c
10
lstate.c
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lstate.c,v 2.9 2004/06/17 14:06:52 roberto Exp roberto $
|
** $Id: lstate.c,v 2.10 2004/06/17 14:25:31 roberto Exp roberto $
|
||||||
** Global State
|
** Global State
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@ -122,9 +122,10 @@ static void preinit_state (lua_State *L, global_State *g) {
|
|||||||
static void close_state (lua_State *L) {
|
static void close_state (lua_State *L) {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
luaF_close(L, L->stack); /* close all upvalues for this thread */
|
luaF_close(L, L->stack); /* close all upvalues for this thread */
|
||||||
luaC_sweepall(L); /* collect all elements */
|
luaC_freeall(L); /* collect all objects */
|
||||||
lua_assert(g->rootgc == obj2gco(L));
|
lua_assert(g->rootgc == NULL);
|
||||||
luaS_freeall(L);
|
lua_assert(g->strt.nuse == 0);
|
||||||
|
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *);
|
||||||
luaZ_freebuffer(L, &g->buff);
|
luaZ_freebuffer(L, &g->buff);
|
||||||
freestack(L, L);
|
freestack(L, L);
|
||||||
lua_assert(g->nblocks == sizeof(LG));
|
lua_assert(g->nblocks == sizeof(LG));
|
||||||
@ -177,6 +178,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
|||||||
luaZ_initbuffer(L, &g->buff);
|
luaZ_initbuffer(L, &g->buff);
|
||||||
g->panic = NULL;
|
g->panic = NULL;
|
||||||
g->gcstate = GCSfinalize;
|
g->gcstate = GCSfinalize;
|
||||||
|
g->gcgenerational = 0;
|
||||||
g->rootgc = obj2gco(L);
|
g->rootgc = obj2gco(L);
|
||||||
g->sweepstrgc = 0;
|
g->sweepstrgc = 0;
|
||||||
g->sweepgc = &g->rootgc;
|
g->sweepgc = &g->rootgc;
|
||||||
|
7
lstate.h
7
lstate.h
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lstate.h,v 2.4 2004/05/31 18:51:50 roberto Exp roberto $
|
** $Id: lstate.h,v 2.5 2004/06/02 19:07:55 roberto Exp roberto $
|
||||||
** Global State
|
** Global State
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@ -69,7 +69,9 @@ typedef struct global_State {
|
|||||||
stringtable strt; /* hash table for strings */
|
stringtable strt; /* hash table for strings */
|
||||||
lua_Alloc realloc; /* function to reallocate memory */
|
lua_Alloc realloc; /* function to reallocate memory */
|
||||||
void *ud; /* auxiliary data to `realloc' */
|
void *ud; /* auxiliary data to `realloc' */
|
||||||
int currentwhite;
|
lu_byte currentwhite;
|
||||||
|
lu_byte gcstate; /* state of garbage collector */
|
||||||
|
lu_byte gcgenerational;
|
||||||
GCObject *rootgc; /* list of all collectable objects */
|
GCObject *rootgc; /* list of all collectable objects */
|
||||||
GCObject *firstudata; /* udata go to the end of `rootgc' */
|
GCObject *firstudata; /* udata go to the end of `rootgc' */
|
||||||
GCObject **sweepgc; /* position of sweep in `rootgc' */
|
GCObject **sweepgc; /* position of sweep in `rootgc' */
|
||||||
@ -78,7 +80,6 @@ typedef struct global_State {
|
|||||||
GCObject *grayagain; /* list of objects to be traversed atomically */
|
GCObject *grayagain; /* list of objects to be traversed atomically */
|
||||||
GCObject *weak; /* list of weak tables (to be cleared) */
|
GCObject *weak; /* list of weak tables (to be cleared) */
|
||||||
GCObject *tmudata; /* list of userdata to be GC */
|
GCObject *tmudata; /* list of userdata to be GC */
|
||||||
int gcstate; /* state of garbage collector */
|
|
||||||
Mbuffer buff; /* temporary buffer for string concatentation */
|
Mbuffer buff; /* temporary buffer for string concatentation */
|
||||||
lu_mem GCthreshold;
|
lu_mem GCthreshold;
|
||||||
lu_mem nblocks; /* number of `bytes' currently allocated */
|
lu_mem nblocks; /* number of `bytes' currently allocated */
|
||||||
|
11
lstring.c
11
lstring.c
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lstring.c,v 2.1 2003/12/10 12:13:36 roberto Exp roberto $
|
** $Id: lstring.c,v 2.2 2004/04/30 20:13:38 roberto Exp roberto $
|
||||||
** String table (keeps all strings handled by Lua)
|
** String table (keeps all strings handled by Lua)
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@ -19,17 +19,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void luaS_freeall (lua_State *L) {
|
|
||||||
lua_assert(G(L)->strt.nuse==0);
|
|
||||||
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void luaS_resize (lua_State *L, int newsize) {
|
void luaS_resize (lua_State *L, int newsize) {
|
||||||
GCObject **newhash;
|
GCObject **newhash;
|
||||||
stringtable *tb;
|
stringtable *tb;
|
||||||
int i;
|
int i;
|
||||||
if (G(L)->sweepstrgc > 0) return; /* cannot resize during GC traverse */
|
if (G(L)->gcstate == GCSsweepstring)
|
||||||
|
return; /* cannot resize during GC traverse */
|
||||||
newhash = luaM_newvector(L, newsize, GCObject *);
|
newhash = luaM_newvector(L, newsize, GCObject *);
|
||||||
tb = &G(L)->strt;
|
tb = &G(L)->strt;
|
||||||
for (i=0; i<newsize; i++) newhash[i] = NULL;
|
for (i=0; i<newsize; i++) newhash[i] = NULL;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lstring.h,v 1.37 2002/08/16 14:45:55 roberto Exp roberto $
|
** $Id: lstring.h,v 1.38 2003/11/17 19:50:05 roberto Exp roberto $
|
||||||
** String table (keep all strings handled by Lua)
|
** String table (keep all strings handled by Lua)
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@ -26,7 +26,6 @@
|
|||||||
|
|
||||||
void luaS_resize (lua_State *L, int newsize);
|
void luaS_resize (lua_State *L, int newsize);
|
||||||
Udata *luaS_newudata (lua_State *L, size_t s);
|
Udata *luaS_newudata (lua_State *L, size_t s);
|
||||||
void luaS_freeall (lua_State *L);
|
|
||||||
TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
|
TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
|
||||||
|
|
||||||
|
|
||||||
|
16
ltests.c
16
ltests.c
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: ltests.c,v 2.9 2004/06/02 19:08:52 roberto Exp roberto $
|
** $Id: ltests.c,v 2.10 2004/07/09 18:23:17 roberto Exp roberto $
|
||||||
** Internal Module for Debugging of the Lua Implementation
|
** Internal Module for Debugging of the Lua Implementation
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@ -153,9 +153,9 @@ void *debug_realloc (void *ud, void *block, size_t oldsize, size_t size) {
|
|||||||
|
|
||||||
static int testobjref1 (global_State *g, GCObject *f, GCObject *t) {
|
static int testobjref1 (global_State *g, GCObject *f, GCObject *t) {
|
||||||
if (isdead(g,t)) return 0;
|
if (isdead(g,t)) return 0;
|
||||||
if (g->gcstate == GCSpropagate)
|
if (g->gcstate == GCSpropagate || g->gcgenerational)
|
||||||
return !isblack(f) || !iswhite(t);
|
return !isblack(f) || !iswhite(t);
|
||||||
else if (g->gcstate == GCSfinalize)
|
else if (g->gcstate == GCSfinalize && !g->gcgenerational)
|
||||||
return iswhite(f);
|
return iswhite(f);
|
||||||
else
|
else
|
||||||
return 1;
|
return 1;
|
||||||
@ -175,7 +175,8 @@ static void printobj (global_State *g, GCObject *o) {
|
|||||||
static int testobjref (global_State *g, GCObject *f, GCObject *t) {
|
static int testobjref (global_State *g, GCObject *f, GCObject *t) {
|
||||||
int r = testobjref1(g,f,t);
|
int r = testobjref1(g,f,t);
|
||||||
if (!r) {
|
if (!r) {
|
||||||
printf("%d(%02X) - ", g->gcstate, g->currentwhite);
|
printf("%d(%02X) %c - ", g->gcstate, g->currentwhite,
|
||||||
|
g->gcgenerational ? 'G' : ' ');
|
||||||
printobj(g, f);
|
printobj(g, f);
|
||||||
printf("\t-> ");
|
printf("\t-> ");
|
||||||
printobj(g, t);
|
printobj(g, t);
|
||||||
@ -290,9 +291,12 @@ static void checkstack (global_State *g, lua_State *L1) {
|
|||||||
|
|
||||||
static void checkobject (global_State *g, GCObject *o) {
|
static void checkobject (global_State *g, GCObject *o) {
|
||||||
if (isdead(g, o))
|
if (isdead(g, o))
|
||||||
lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep);
|
/* lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep);*/
|
||||||
|
{ if (!(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep))
|
||||||
|
printf(">>> %d %s %02x\n", g->gcstate, luaT_typenames[o->gch.tt], o->gch.marked);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if (g->gcstate == GCSfinalize)
|
if (g->gcstate == GCSfinalize && !g->gcgenerational)
|
||||||
lua_assert(iswhite(o));
|
lua_assert(iswhite(o));
|
||||||
switch (o->gch.tt) {
|
switch (o->gch.tt) {
|
||||||
case LUA_TUPVAL: {
|
case LUA_TUPVAL: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user