commit 4433dbb5f5ac0bb6118bc49ddf061f194c070814
parent 5cb128ea540b33dbc6be659d5dfc3c64c57d78d9
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Wed, 24 Mar 2010 10:06:37 -0300
userdata with finalizers are kept in a separated list ('udgc'), instead
of at the end of 'rootgc' (which was renamed to 'allgc', as it is not
"root" in the usual meaning for collectors)
Diffstat:
5 files changed, 48 insertions(+), 44 deletions(-)
diff --git a/lgc.c b/lgc.c
@@ -1,5 +1,5 @@
/*
-** $Id: lgc.c,v 2.68 2010/03/22 18:28:03 roberto Exp $
+** $Id: lgc.c,v 2.69 2010/03/23 20:16:06 roberto Exp roberto $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -33,8 +33,10 @@
#define maskcolors (~(bitmask(BLACKBIT)|WHITEBITS))
-#define makewhite(g,x) \
- (gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | luaC_white(g)))
+#define makewhitew(w,x) \
+ (gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | (w)))
+
+#define makewhite(g,x) makewhitew(luaC_white(g), x)
#define white2gray(x) resetbits(gch(x)->marked, WHITEBITS)
#define black2gray(x) resetbit(gch(x)->marked, BLACKBIT)
@@ -127,7 +129,7 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list,
global_State *g = G(L);
GCObject *o = obj2gco(cast(char *, luaM_newobject(L, tt, sz)) + offset);
if (list == NULL)
- list = &g->rootgc; /* standard list for collectable objects */
+ list = &g->allgc; /* standard list for collectable objects */
gch(o)->marked = luaC_white(g);
gch(o)->tt = tt;
gch(o)->next = *list;
@@ -139,8 +141,8 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list,
void luaC_linkupval (lua_State *L, UpVal *uv) {
global_State *g = G(L);
GCObject *o = obj2gco(uv);
- gch(o)->next = g->rootgc; /* link upvalue into `rootgc' list */
- g->rootgc = o;
+ gch(o)->next = g->allgc; /* link upvalue into `allgc' list */
+ g->allgc = o;
if (isgray(o)) {
if (g->gcstate == GCSpropagate) {
gray2black(o); /* closed upvalues need barrier */
@@ -549,8 +551,9 @@ static void sweepthread (lua_State *L, lua_State *L1, int alive) {
static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
GCObject *curr;
global_State *g = G(L);
- int deadmask = otherwhite(g);
int gckind = g->gckind;
+ int deadmask = otherwhite(g);
+ int white = luaC_white(g);
while ((curr = *p) != NULL && count-- > 0) {
int alive = (gch(curr)->marked ^ WHITEBITS) & deadmask;
if (gch(curr)->tt == LUA_TTHREAD)
@@ -559,7 +562,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
lua_assert(!isdead(g, curr) || testbit(gch(curr)->marked, FIXEDBIT));
/* in generational mode all live objects are kept black, which
means they grow to old generation */
- if (gckind != KGC_GEN) makewhite(g, curr);
+ if (gckind != KGC_GEN) makewhitew(white, curr);
p = &gch(curr)->next;
}
else { /* must erase `curr' */
@@ -597,8 +600,8 @@ static void checkSizes (lua_State *L) {
static Udata *udata2finalize (global_State *g) {
GCObject *o = g->tobefnz; /* get first element */
g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */
- gch(o)->next = g->rootgc; /* return it to `root' list */
- g->rootgc = o;
+ gch(o)->next = g->allgc; /* return it to 'allgc' list */
+ g->allgc = o;
lua_assert(isfinalized(gch(o)));
resetbit(gch(o)->marked, SEPARATED); /* mark it as such */
makewhite(g, o);
@@ -643,7 +646,7 @@ static void GCTM (lua_State *L, int propagateerrors) {
/* move 'dead' udata that need finalization to list 'tobefnz' */
void luaC_separateudata (lua_State *L, int all) {
global_State *g = G(L);
- GCObject **p = &g->mainthread->next;
+ GCObject **p = &g->udgc;
GCObject *curr;
GCObject **lastnext = &g->tobefnz;
/* find last 'next' field in 'tobefnz' list (to insert elements in its end) */
@@ -655,7 +658,7 @@ void luaC_separateudata (lua_State *L, int all) {
p = &gch(curr)->next; /* don't bother with it */
else {
l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */
- *p = gch(curr)->next; /* remove 'curr' from 'rootgc' list */
+ *p = gch(curr)->next; /* remove 'curr' from 'udgc' list */
/* link 'curr' at the end of 'tobefnz' list */
gch(curr)->next = *lastnext;
*lastnext = curr;
@@ -671,13 +674,12 @@ void luaC_checkfinalizer (lua_State *L, Udata *u) {
isfinalized(&u->uv) || /* ... or is finalized... */
gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */
return; /* nothing to be done */
- else { /* move 'u' to 2nd part of root list */
+ else { /* move 'u' to 'udgc' list */
GCObject **p;
- for (p = &g->rootgc; *p != obj2gco(u); p = &gch(*p)->next)
- lua_assert(*p != obj2gco(g->mainthread)); /* 'u' must be in this list */
+ for (p = &g->allgc; *p != obj2gco(u); p = &gch(*p)->next) ;
*p = u->uv.next; /* remove 'u' from root list */
- u->uv.next = g->mainthread->next; /* re-link it in list */
- g->mainthread->next = obj2gco(u);
+ u->uv.next = g->udgc; /* re-link it in list */
+ g->udgc = obj2gco(u);
l_setbit(u->uv.marked, SEPARATED); /* mark it as such */
}
}
@@ -697,8 +699,9 @@ void luaC_freeallobjects (lua_State *L) {
while (g->tobefnz) GCTM(L, 0); /* Call all pending finalizers */
/* following "white" makes all objects look dead */
g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT);
- sweepwholelist(L, &g->rootgc);
- lua_assert(g->rootgc == obj2gco(g->mainthread) &&
+ sweepwholelist(L, &g->udgc);
+ sweepwholelist(L, &g->allgc);
+ lua_assert(g->allgc == obj2gco(g->mainthread) &&
g->mainthread->next == NULL);
for (i = 0; i < g->strt.size; i++) /* free all string lists */
sweepwholelist(L, &g->strt.hash[i]);
@@ -761,19 +764,21 @@ static l_mem singlestep (lua_State *L) {
return GCSWEEPCOST;
}
else { /* nothing more to sweep */
- g->sweepgc = &g->rootgc;
- g->gcstate = GCSsweep; /* sweep all other objects */
+ g->sweepgc = &g->udgc; /* sweep all userdata */
+ g->gcstate = GCSsweepudata;
+ checkSizes(L);
return 0;
}
}
+ case GCSsweepudata:
case GCSsweep: {
if (*g->sweepgc) {
g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
return GCSWEEPMAX*GCSWEEPCOST;
}
- else { /* nothing more to sweep */
- checkSizes(L);
- g->gcstate = GCSfinalize; /* end sweep phase */
+ else { /* go to next phase */
+ g->sweepgc = &g->allgc; /* useless (but harmless) in GCSsweep case */
+ g->gcstate = (g->gcstate == GCSsweep) ? GCSfinalize : GCSsweep;
return 0;
}
}
@@ -856,8 +861,7 @@ void luaC_fullgc (lua_State *L, int isemergency) {
g->gcstate = GCSsweepstring;
}
/* finish any pending sweep phase */
- luaC_runtilstate(L, ~bit2mask(GCSsweepstring, GCSsweep));
- lua_assert(g->gcstate == GCSpause || g->gcstate == GCSfinalize);
+ luaC_runtilstate(L, bit2mask(GCSpause, GCSfinalize));
g->gcstate = GCSpause; /* start a new collection */
/* run collector up to finalizers */
luaC_runtilstate(L, bitmask(GCSfinalize));
diff --git a/lgc.h b/lgc.h
@@ -1,5 +1,5 @@
/*
-** $Id: lgc.h,v 2.26 2009/12/11 21:31:14 roberto Exp roberto $
+** $Id: lgc.h,v 2.27 2009/12/16 16:42:58 roberto Exp roberto $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -18,8 +18,9 @@
#define GCSpropagate 1
#define GCSatomic 2
#define GCSsweepstring 3
-#define GCSsweep 4
-#define GCSfinalize 5
+#define GCSsweepudata 4
+#define GCSsweep 5
+#define GCSfinalize 6
@@ -45,12 +46,10 @@
** bit 1 - object is white (type 1)
** bit 2 - object is black
** bit 3 - for userdata: has been finalized
-** bit 4 - for userdata: it's in 2nd part of rootgc list or in tobefnz
+** bit 4 - for userdata: it's in 'udgc' list or in 'tobefnz'
** bit 5 - object is fixed (should not be collected)
** bit 6 - object is "super" fixed (only the main thread)
*/
-
-
#define WHITE0BIT 0
#define WHITE1BIT 1
#define BLACKBIT 2
@@ -58,6 +57,7 @@
#define SEPARATED 4
#define FIXEDBIT 5
#define SFIXEDBIT 6
+
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
diff --git a/lstate.c b/lstate.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstate.c,v 2.70 2010/03/19 21:04:17 roberto Exp roberto $
+** $Id: lstate.c,v 2.71 2010/03/22 17:45:55 roberto Exp roberto $
** Global State
** See Copyright Notice in lua.h
*/
@@ -264,7 +264,8 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->panic = NULL;
g->version = lua_version(NULL);
g->gcstate = GCSpause;
- g->rootgc = obj2gco(L);
+ g->allgc = obj2gco(L);
+ g->udgc = NULL;
g->tobefnz = NULL;
g->totalbytes = sizeof(LG);
g->gcpause = LUAI_GCPAUSE;
diff --git a/lstate.h b/lstate.h
@@ -1,5 +1,5 @@
/*
-** $Id: lstate.h,v 2.54 2010/03/13 15:55:42 roberto Exp roberto $
+** $Id: lstate.h,v 2.55 2010/03/22 18:28:03 roberto Exp roberto $
** Global State
** See Copyright Notice in lua.h
*/
@@ -19,7 +19,7 @@
** Some notes about garbage-collected objects: All objects in Lua must
** be kept somehow accessible until being freed.
**
-** Lua keeps most objects linked in list g->rootgc. The link uses field
+** Lua keeps most objects linked in list g->allgc. The link uses field
** 'next' of the CommonHeader.
**
** Strings are kept in several lists headed by the array g->strt.hash.
@@ -32,9 +32,7 @@
** when traversing the respective threads, but the thread may already be
** dead, while the upvalue is still accessible through closures.)
**
-** Userdata with finalizers are kept in the list g->rootgc, but after
-** the mainthread, which should be otherwise the last element in the
-** list, as it was the first one inserted there.
+** Userdata with finalizers are kept in the list g->udgc.
**
** The list g->tobefnz links all userdata being finalized.
@@ -124,7 +122,8 @@ typedef struct global_State {
lu_byte gcstate; /* state of garbage collector */
lu_byte gckind; /* kind of GC running */
int sweepstrgc; /* position of sweep in `strt' */
- GCObject *rootgc; /* list of all collectable objects */
+ GCObject *allgc; /* list of all collectable objects */
+ GCObject *udgc; /* list of collectable userdata with finalizers */
GCObject **sweepgc; /* current position of sweep */
GCObject *gray; /* list of gray objects */
GCObject *grayagain; /* list of objects to be traversed atomically */
diff --git a/ltests.c b/ltests.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltests.c,v 2.86 2009/12/22 15:32:50 roberto Exp roberto $
+** $Id: ltests.c,v 2.87 2010/01/13 16:18:25 roberto Exp roberto $
** Internal Module for Debugging of the Lua Implementation
** See Copyright Notice in lua.h
*/
@@ -188,7 +188,7 @@ static int testobjref1 (global_State *g, GCObject *f, GCObject *t) {
static void printobj (global_State *g, GCObject *o) {
int i = 0;
GCObject *p;
- for (p = g->rootgc; p != o && p != NULL; p = gch(p)->next) i++;
+ for (p = g->allgc; p != o && p != NULL; p = gch(p)->next) i++;
if (p == NULL) i = -1;
printf("%d:%s(%p)-%c(%02X)", i, typename(gch(o)->tt), (void *)o,
isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', gch(o)->marked);
@@ -375,12 +375,12 @@ int lua_checkmemory (lua_State *L) {
checkliveness(g, &g->l_registry);
lua_assert(!isdead(g, obj2gco(g->l_gt)));
checkstack(g, g->mainthread);
- for (o = g->rootgc; o != obj2gco(g->mainthread); o = gch(o)->next) {
+ for (o = g->allgc; o != obj2gco(g->mainthread); o = gch(o)->next) {
lua_assert(!testbits(o->gch.marked, bit2mask(SEPARATED, SFIXEDBIT)));
checkobject(g, o);
}
lua_assert(testbit(o->gch.marked, SFIXEDBIT));
- for (o = gch(o)->next; o != NULL; o = gch(o)->next) {
+ for (o = g->udgc; o != NULL; o = gch(o)->next) {
lua_assert(gch(o)->tt == LUA_TUSERDATA &&
!isdead(g, o) &&
testbit(o->gch.marked, SEPARATED));