'luaC_linkupval' moved into 'lfunc.c' code + new way to control GC speed

This commit is contained in:
Roberto Ierusalimschy 2010-04-29 14:32:40 -03:00
parent 3eb1788bb4
commit aaa5d7adab
2 changed files with 80 additions and 80 deletions

130
lgc.c
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lgc.c,v 2.79 2010/04/20 20:15:30 roberto Exp roberto $ ** $Id: lgc.c,v 2.80 2010/04/26 17:58:00 roberto Exp roberto $
** Garbage Collector ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -23,16 +23,19 @@
#include "ltm.h" #include "ltm.h"
#define GCSTEPSIZE 1024u #define GCSTEPSIZE 1024
#define GCSWEEPMAX 40 #define GCSWEEPMAX 40
#define GCSWEEPCOST 10 #define GCSWEEPCOST 1
#define GCFINALIZECOST 100 #define GCFINALIZECOST 50
#define GCROOTCOST 10 #define GCROOTCOST 10
#define GCATOMICCOST 1000 #define GCATOMICCOST 1000
#define issweepphase(g) \ /*
(GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep) ** standard negative debt for GC; a reasonable "time" to wait before
** starting a new cycle
*/
#define stddebt(g) (-cast(l_mem, g->totalbytes/100) * g->gcpause)
/* /*
@ -60,17 +63,6 @@
#define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \ #define markobject(g,t) { if ((t) && iswhite(obj2gco(t))) \
reallymarkobject(g, obj2gco(t)); } reallymarkobject(g, obj2gco(t)); }
/*
** macro to tell when main invariant (white objects cannot point to black
** ones) must be kept. During a non-generational collection, the sweep
** phase may brak the invariant, as objects turned white may point to
** still-black objects. The invariant is restored when sweep ends and
** all objects are white again. During a generational collection, the
** invariant must be kept all times.
*/
#define keepinvariant(g) (g->gckind == KGC_GEN || g->gcstate == GCSpropagate)
static void reallymarkobject (global_State *g, GCObject *o); static void reallymarkobject (global_State *g, GCObject *o);
@ -142,10 +134,16 @@ void luaC_barrierback (lua_State *L, Table *t) {
global_State *g = G(L); global_State *g = G(L);
GCObject *o = obj2gco(t); GCObject *o = obj2gco(t);
lua_assert(isblack(o) && !isdead(g, o)); lua_assert(isblack(o) && !isdead(g, o));
if (keepinvariant(g)) {
black2gray(o); /* make table gray (again) */ black2gray(o); /* make table gray (again) */
t->gclist = g->grayagain; t->gclist = g->grayagain;
g->grayagain = o; g->grayagain = o;
} }
else { /* sweep phase */
lua_assert(issweepphase(g));
makewhite(g, o); /* mark main obj. as white to avoid other barriers */
}
}
/* /*
@ -166,23 +164,6 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list,
return o; return o;
} }
/*
** link an upvalue back to the main root list. (It was previously in the
** list of open upvalues of some thread.)
*/
void luaC_linkupval (lua_State *L, UpVal *uv) {
global_State *g = G(L);
GCObject *o = obj2gco(uv);
gch(o)->next = g->allgc; /* link upvalue into `allgc' list */
g->allgc = o;
lua_assert(!isblack(o)); /* open upvalues are never black */
if (isgray(o)) { /* is it marked? */
gray2black(o); /* could not be black; now it can */
luaC_barrier(L, uv, uv->v);
}
}
/* }====================================================== */ /* }====================================================== */
@ -287,9 +268,9 @@ static void remarkupvals (global_State *g) {
*/ */
static void markroot (lua_State *L) { static void markroot (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
g->gray = NULL; lua_assert(g->gckind == KGC_GEN ||
g->grayagain = NULL; (g->gray == NULL && g->grayagain == NULL && g->weak == NULL &&
g->weak = g->ephemeron = g->allweak = NULL; g->allweak == NULL && g->ephemeron == NULL));
markobject(g, g->mainthread); markobject(g, g->mainthread);
markvalue(g, &g->l_registry); markvalue(g, &g->l_registry);
markmt(g); markmt(g);
@ -372,7 +353,7 @@ static void traversestrongtable (global_State *g, Table *h) {
} }
static void traversetable (global_State *g, Table *h) { static int traversetable (global_State *g, Table *h) {
const TValue *mode = gfasttm(g, h->metatable, TM_MODE); const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
markobject(g, h->metatable); markobject(g, h->metatable);
if (mode && ttisstring(mode)) { /* is there a weak mode? */ if (mode && ttisstring(mode)) { /* is there a weak mode? */
@ -380,20 +361,26 @@ static void traversetable (global_State *g, Table *h) {
int weakvalue = (strchr(svalue(mode), 'v') != NULL); int weakvalue = (strchr(svalue(mode), 'v') != NULL);
if (weakkey || weakvalue) { /* is really weak? */ if (weakkey || weakvalue) { /* is really weak? */
black2gray(obj2gco(h)); /* keep table gray */ black2gray(obj2gco(h)); /* keep table gray */
if (!weakkey) /* strong keys? */ if (!weakkey) { /* strong keys? */
traverseweakvalue(g, h); traverseweakvalue(g, h);
else if (!weakvalue) /* strong values? */ return 1 + sizenode(h);
}
else if (!weakvalue) { /* strong values? */
traverseephemeron(g, h); traverseephemeron(g, h);
else return 1 + h->sizearray + sizenode(h);
}
else {
linktable(h, &g->allweak); /* nothing to traverse now */ linktable(h, &g->allweak); /* nothing to traverse now */
return; return 1;
}
} /* else go through */ } /* else go through */
} }
traversestrongtable(g, h); traversestrongtable(g, h);
return 1 + h->sizearray + (2 * sizenode(h));
} }
static void traverseproto (global_State *g, Proto *f) { static int traverseproto (global_State *g, Proto *f) {
int i; int i;
stringmark(f->source); stringmark(f->source);
for (i = 0; i < f->sizek; i++) /* mark literals */ for (i = 0; i < f->sizek; i++) /* mark literals */
@ -404,6 +391,7 @@ static void traverseproto (global_State *g, Proto *f) {
markobject(g, f->p[i]); markobject(g, f->p[i]);
for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */
stringmark(f->locvars[i].varname); stringmark(f->locvars[i].varname);
return 1 + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars;
} }
@ -425,26 +413,27 @@ static l_mem traverseclosure (global_State *g, Closure *cl) {
} }
static void traversestack (global_State *g, lua_State *L) { static int traversestack (global_State *g, lua_State *L) {
StkId o; StkId o = L->stack;
if (L->stack == NULL) if (L->stack == NULL)
return; /* stack not completely built yet */ return 1; /* stack not completely built yet */
for (o = L->stack; o < L->top; o++) for (; o < L->top; o++)
markvalue(g, o); markvalue(g, o);
if (g->gcstate == GCSatomic) { /* final traversal? */ if (g->gcstate == GCSatomic) { /* final traversal? */
StkId lim = L->stack + L->stacksize; /* real end of stack */ StkId lim = L->stack + L->stacksize; /* real end of stack */
for (; o < lim; o++) /* clear not-marked stack slice */ for (; o < lim; o++) /* clear not-marked stack slice */
setnilvalue(o); setnilvalue(o);
} }
return 1 + cast_int(o - L->stack);
} }
/* /*
** traverse one gray object, turning it to black (except for threads, ** traverse one gray object, turning it to black (except for threads,
** which are always gray). ** which are always gray).
** Returns 'quantity' traversed. ** Returns number of values traversed.
*/ */
static l_mem propagatemark (global_State *g) { static int propagatemark (global_State *g) {
GCObject *o = g->gray; GCObject *o = g->gray;
lua_assert(isgray(o)); lua_assert(isgray(o));
gray2black(o); gray2black(o);
@ -452,9 +441,7 @@ static l_mem propagatemark (global_State *g) {
case LUA_TTABLE: { case LUA_TTABLE: {
Table *h = gco2t(o); Table *h = gco2t(o);
g->gray = h->gclist; g->gray = h->gclist;
traversetable(g, h); return traversetable(g, h);
return sizeof(Table) + sizeof(TValue) * h->sizearray +
sizeof(Node) * sizenode(h);
} }
case LUA_TFUNCTION: { case LUA_TFUNCTION: {
Closure *cl = gco2cl(o); Closure *cl = gco2cl(o);
@ -467,19 +454,12 @@ static l_mem propagatemark (global_State *g) {
th->gclist = g->grayagain; th->gclist = g->grayagain;
g->grayagain = o; g->grayagain = o;
black2gray(o); black2gray(o);
traversestack(g, th); return traversestack(g, th);
return sizeof(lua_State) + sizeof(TValue) * th->stacksize;
} }
case LUA_TPROTO: { case LUA_TPROTO: {
Proto *p = gco2p(o); Proto *p = gco2p(o);
g->gray = p->gclist; g->gray = p->gclist;
traverseproto(g, p); return 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;
} }
default: lua_assert(0); return 0; default: lua_assert(0); return 0;
} }
@ -673,15 +653,15 @@ static void GCTM (lua_State *L, int propagateerrors) {
if (tm != NULL && ttisfunction(tm)) { /* is there a finalizer? */ if (tm != NULL && ttisfunction(tm)) { /* is there a finalizer? */
int status; int status;
lu_byte oldah = L->allowhook; lu_byte oldah = L->allowhook;
lu_mem oldt = g->GCthreshold; lu_mem oldd = g->GCdebt;
L->allowhook = 0; /* stop debug hooks during GC tag method */ L->allowhook = 0; /* stop debug hooks during GC tag method */
g->GCthreshold = 2 * g->totalbytes; /* avoid GC steps */ g->GCdebt = -2 * g->totalbytes; /* avoid GC steps */
setobj2s(L, L->top, tm); /* push finalizer... */ setobj2s(L, L->top, tm); /* push finalizer... */
setuvalue(L, L->top+1, udata); /* ... and its argument */ setuvalue(L, L->top+1, udata); /* ... and its argument */
L->top += 2; /* and (next line) call the finalizer */ L->top += 2; /* and (next line) call the finalizer */
status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
L->allowhook = oldah; /* restore hooks */ L->allowhook = oldah; /* restore hooks */
g->GCthreshold = oldt; /* restore threshold */ g->GCdebt = oldd; /* restore threshold */
if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ if (status != LUA_OK && propagateerrors) { /* error while running __gc? */
if (status == LUA_ERRRUN) { /* is there an error msg.? */ if (status == LUA_ERRRUN) { /* is there an error msg.? */
luaO_pushfstring(L, "error in __gc tag method (%s)", luaO_pushfstring(L, "error in __gc tag method (%s)",
@ -791,7 +771,13 @@ static void atomic (lua_State *L) {
cleartable(g->weak); cleartable(g->weak);
cleartable(g->ephemeron); cleartable(g->ephemeron);
cleartable(g->allweak); cleartable(g->allweak);
lua_checkmemory(L);
g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
if (g->gckind != KGC_GEN) {
g->gray = NULL; /* all gray objects will become white */
g->grayagain = NULL;
g->weak = g->ephemeron = g->allweak = NULL;
}
} }
@ -890,23 +876,18 @@ static void generationalcollection (lua_State *L) {
if (g->totalbytes > g->lastmajormem/100 * g->gcpause) if (g->totalbytes > g->lastmajormem/100 * g->gcpause)
g->lastmajormem = 0; /* signal for a major collection */ g->lastmajormem = 0; /* signal for a major collection */
} }
g->GCthreshold = (g->totalbytes/100) * g->gcpause; g->GCdebt = stddebt(g);
} }
static void step (lua_State *L) { static void step (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; /* how much to work */ l_mem lim = g->gcstepmul; /* how much to work */
lu_mem debt = g->totalbytes - g->GCthreshold;
lua_assert(g->gckind == KGC_NORMAL); lua_assert(g->gckind == KGC_NORMAL);
do { /* always perform at least one single step */ do { /* always perform at least one single step */
lim -= singlestep(L); lim -= singlestep(L);
} while (lim > 0 && g->gcstate != GCSpause); } while (lim > 0 && g->gcstate != GCSpause);
g->GCthreshold = (g->gcstate != GCSpause) g->GCdebt += (g->gcstate != GCSpause) ? -GCSTEPSIZE : stddebt(g);
? g->totalbytes + GCSTEPSIZE
: (g->totalbytes/100) * g->gcpause;
/* compensate if GC is "behind schedule" (has some debt to pay) */
if (g->GCthreshold > debt) g->GCthreshold -= debt;
} }
@ -930,6 +911,9 @@ void luaC_fullgc (lua_State *L, int isemergency) {
(as white has not changed, nothing will be collected) */ (as white has not changed, nothing will be collected) */
g->sweepstrgc = 0; g->sweepstrgc = 0;
g->gcstate = GCSsweepstring; g->gcstate = GCSsweepstring;
g->gray = NULL;
g->grayagain = NULL;
g->weak = g->ephemeron = g->allweak = NULL;
} }
/* finish any pending sweep phase */ /* finish any pending sweep phase */
luaC_runtilstate(L, bit2mask(GCSpause, GCSfinalize)); luaC_runtilstate(L, bit2mask(GCSpause, GCSfinalize));
@ -943,7 +927,7 @@ void luaC_fullgc (lua_State *L, int isemergency) {
g->gcstate = GCSpause; /* collector must be always in... */ g->gcstate = GCSpause; /* collector must be always in... */
luaC_runtilstate(L, bitmask(GCSpropagate)); /* ...propagate phase */ luaC_runtilstate(L, bitmask(GCSpropagate)); /* ...propagate phase */
} }
g->GCthreshold = (g->totalbytes/100) * g->gcpause; g->GCdebt = stddebt(g);
} }
/* }====================================================== */ /* }====================================================== */

24
lgc.h
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lgc.h,v 2.29 2010/03/24 15:51:10 roberto Exp roberto $ ** $Id: lgc.h,v 2.30 2010/03/25 13:06:36 roberto Exp roberto $
** Garbage Collector ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -23,6 +23,24 @@
#define GCSfinalize 6 #define GCSfinalize 6
#define issweepphase(g) \
(GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep)
/*
** macro to tell when main invariant (white objects cannot point to black
** ones) must be kept. During a non-generational collection, the sweep
** phase may brak the invariant, as objects turned white may point to
** still-black objects. The invariant is restored when sweep ends and
** all objects are white again. During a generational collection, the
** invariant must be kept all times.
*/
#define keepinvariant(g) (g->gckind == KGC_GEN || g->gcstate == GCSpropagate)
#define gcstopped(g) ((g)->GCdebt == MIN_LMEM)
#define stopgc(g) ((g)->GCdebt = MIN_LMEM)
/* /*
** some useful bit tricks ** some useful bit tricks
@ -76,8 +94,7 @@
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) #define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
#define luaC_checkGC(L) \ #define luaC_checkGC(L) {condchangemem(L); if (G(L)->GCdebt > 0) luaC_step(L);}
{condchangemem(L); if (G(L)->totalbytes >= G(L)->GCthreshold) luaC_step(L);}
#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ #define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \
@ -100,7 +117,6 @@ LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz,
GCObject **list, int offset); GCObject **list, int offset);
LUAI_FUNC void luaC_linkupval (lua_State *L, UpVal *uv);
LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); LUAI_FUNC void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v);
LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t); LUAI_FUNC void luaC_barrierback (lua_State *L, Table *t);
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, Udata *u); LUAI_FUNC void luaC_checkfinalizer (lua_State *L, Udata *u);