diff --git a/lgc.c b/lgc.c index 52084ab0..796f7b59 100644 --- a/lgc.c +++ b/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.130 2012/05/29 17:52:17 roberto Exp roberto $ +** $Id: lgc.c,v 2.131 2012/05/30 16:01:10 roberto Exp roberto $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -753,6 +753,18 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { return (*p == NULL) ? NULL : p; } + +/* +** sweep a list until a live object (or end of list) +*/ +static GCObject **sweeptolive (lua_State *L, GCObject **p) { + GCObject ** old = p; + do { + p = sweeplist(L, p, 1); + } while (p == old); + return p; +} + /* }====================================================== */ @@ -812,12 +824,14 @@ static void GCTM (lua_State *L, int propagateerrors) { L->allowhook = oldah; /* restore hooks */ g->gcrunning = running; /* restore state */ if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ - if (status == LUA_ERRRUN) { /* is there an error msg.? */ - luaO_pushfstring(L, "error in __gc metamethod (%s)", - lua_tostring(L, -1)); + if (status == LUA_ERRRUN) { /* is there an error object? */ + const char *msg = (ttisstring(L->top - 1)) + ? svalue(L->top - 1) + : "no message"; + luaO_pushfstring(L, "error in __gc metamethod (%s)", msg); status = LUA_ERRGCMM; /* error in __gc metamethod */ } - luaD_throw(L, status); /* re-send error */ + luaD_throw(L, status); /* re-throw error */ } } } @@ -864,11 +878,9 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { else { /* move 'o' to 'finobj' list */ GCObject **p; GCheader *ho = gch(o); - lua_assert(!isdead(g, o)); - /* avoid removing current sweep object */ - if (g->sweepgc == &ho->next) { - /* step to next object in the list */ - g->sweepgc = sweeplist(L, g->sweepgc, 1); + if (g->sweepgc == &ho->next) { /* avoid removing current sweep object */ + lua_assert(issweepphase(g)); + g->sweepgc = sweeptolive(L, g->sweepgc); } /* search for pointer pointing to 'o' */ for (p = &g->allgc; *p != o; p = &gch(*p)->next) { /* empty */ } @@ -899,18 +911,19 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { /* ** enter first sweep phase (strings) and prepare pointers for other -** sweep phases. The calls to 'sweeplist' attempt to make pointers -** point to an object inside the list (instead of to the header), so -** that the real sweep do not need to skip objects created between "now" -** and the start of the real sweep. +** sweep phases. The calls to 'sweeptolive' make pointers point to an +** object inside the list (instead of to the header), so that the real +** sweep do not need to skip objects created between "now" and the start +** of the real sweep. */ static void entersweep (lua_State *L) { global_State *g = G(L); g->gcstate = GCSsweepstring; lua_assert(g->sweepgc == NULL && g->sweepfin == NULL); - g->sweepstrgc = 0; /* prepare to sweep strings, ... */ - g->sweepfin = sweeplist(L, &g->finobj, 1); /* finalizable objects, ... */ - g->sweepgc = sweeplist(L, &g->allgc, 1); /* and regular objects */ + /* prepare to sweep strings, finalizable objects, and regular objects */ + g->sweepstrgc = 0; + g->sweepfin = sweeptolive(L, &g->finobj); + g->sweepgc = sweeptolive(L, &g->allgc); } @@ -966,7 +979,7 @@ void luaC_freeallobjects (lua_State *L) { static l_mem atomic (lua_State *L) { global_State *g = G(L); - l_mem trav = -g->GCmemtrav; /* start counting work */ + l_mem work = -g->GCmemtrav; /* start counting work */ GCObject *origweak, *origall; lua_assert(!iswhite(obj2gco(g->mainthread))); markobject(g, L); /* mark running thread */ @@ -976,20 +989,21 @@ static l_mem atomic (lua_State *L) { /* remark occasional upvalues of (maybe) dead threads */ remarkupvals(g); propagateall(g); /* propagate changes */ - trav += g->GCmemtrav; /* count work done til now */ + work += g->GCmemtrav; /* stop counting (do not (re)count grays) */ /* traverse objects caught by write barrier and by 'remarkupvals' */ retraversegrays(g); + work -= g->GCmemtrav; /* restart counting */ convergeephemerons(g); /* at this point, all strongly accessible objects are marked. */ /* clear values from weak tables, before checking finalizers */ clearvalues(g, g->weak, NULL); clearvalues(g, g->allweak, NULL); origweak = g->weak; origall = g->allweak; - trav -= g->GCmemtrav; /* restart counting work */ + work += g->GCmemtrav; /* stop counting (objects being finalized) */ separatetobefnz(L, 0); /* separate objects to be finalized */ markbeingfnz(g); /* mark objects that will be finalized */ propagateall(g); /* remark, to propagate `preserveness' */ - trav += g->GCmemtrav; /* add work done til now */ + work -= g->GCmemtrav; /* restart counting */ convergeephemerons(g); /* at this point, all resurrected objects are marked. */ /* remove dead objects from weak tables */ @@ -999,8 +1013,8 @@ static l_mem atomic (lua_State *L) { clearvalues(g, g->weak, origweak); clearvalues(g, g->allweak, origall); g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ - entersweep(L); /* prepare to sweep strings */ - return trav; /* estimate of the objects marked by 'atomic' */ + work += g->GCmemtrav; /* complete counting */ + return work; /* estimate of memory marked by 'atomic' */ } @@ -1024,9 +1038,13 @@ static lu_mem singlestep (lua_State *L) { return g->GCmemtrav - oldtrav; /* memory traversed in this step */ } else { /* no more `gray' objects */ + lu_mem work; g->gcstate = GCSatomic; /* finish mark phase */ - g->GCestimate = g->GCmemtrav; /* save what was counted */ - return atomic(L); + g->GCestimate = g->GCmemtrav; /* save what was counted */; + work = atomic(L); /* add what was traversed by 'atomic' */ + g->GCestimate += work; /* estimate of total memory traversed */ + entersweep(L); + return work + 2 * GCSWEEPCOST; } } case GCSsweepstring: { @@ -1095,7 +1113,7 @@ static void generationalcollection (lua_State *L) { } -static void step (lua_State *L) { +static void incstep (lua_State *L) { global_State *g = G(L); l_mem debt = g->GCdebt; int stepmul = g->gcstepmul; @@ -1122,7 +1140,7 @@ void luaC_forcestep (lua_State *L) { global_State *g = G(L); int i; if (isgenerational(g)) generationalcollection(L); - else step(L); + else incstep(L); /* run a few finalizers (or all of them at the end of a collect cycle) */ for (i = 0; g->tobefnz && (i < GCFINALIZENUM || g->gcstate == GCSpause); i++) GCTM(L, 1); /* call one finalizer */