mirror of https://github.com/rusefi/lua.git
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)
This commit is contained in:
parent
5cb128ea54
commit
4433dbb5f5
56
lgc.c
56
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));
|
||||
|
|
12
lgc.h
12
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)
|
||||
|
||||
|
||||
|
|
5
lstate.c
5
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;
|
||||
|
|
11
lstate.h
11
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 */
|
||||
|
|
8
ltests.c
8
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));
|
||||
|
|
Loading…
Reference in New Issue