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
|
** Garbage Collector
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -33,8 +33,10 @@
|
||||||
|
|
||||||
#define maskcolors (~(bitmask(BLACKBIT)|WHITEBITS))
|
#define maskcolors (~(bitmask(BLACKBIT)|WHITEBITS))
|
||||||
|
|
||||||
#define makewhite(g,x) \
|
#define makewhitew(w,x) \
|
||||||
(gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | luaC_white(g)))
|
(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 white2gray(x) resetbits(gch(x)->marked, WHITEBITS)
|
||||||
#define black2gray(x) resetbit(gch(x)->marked, BLACKBIT)
|
#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);
|
global_State *g = G(L);
|
||||||
GCObject *o = obj2gco(cast(char *, luaM_newobject(L, tt, sz)) + offset);
|
GCObject *o = obj2gco(cast(char *, luaM_newobject(L, tt, sz)) + offset);
|
||||||
if (list == NULL)
|
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)->marked = luaC_white(g);
|
||||||
gch(o)->tt = tt;
|
gch(o)->tt = tt;
|
||||||
gch(o)->next = *list;
|
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) {
|
void luaC_linkupval (lua_State *L, UpVal *uv) {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
GCObject *o = obj2gco(uv);
|
GCObject *o = obj2gco(uv);
|
||||||
gch(o)->next = g->rootgc; /* link upvalue into `rootgc' list */
|
gch(o)->next = g->allgc; /* link upvalue into `allgc' list */
|
||||||
g->rootgc = o;
|
g->allgc = o;
|
||||||
if (isgray(o)) {
|
if (isgray(o)) {
|
||||||
if (g->gcstate == GCSpropagate) {
|
if (g->gcstate == GCSpropagate) {
|
||||||
gray2black(o); /* closed upvalues need barrier */
|
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) {
|
static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
|
||||||
GCObject *curr;
|
GCObject *curr;
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
int deadmask = otherwhite(g);
|
|
||||||
int gckind = g->gckind;
|
int gckind = g->gckind;
|
||||||
|
int deadmask = otherwhite(g);
|
||||||
|
int white = luaC_white(g);
|
||||||
while ((curr = *p) != NULL && count-- > 0) {
|
while ((curr = *p) != NULL && count-- > 0) {
|
||||||
int alive = (gch(curr)->marked ^ WHITEBITS) & deadmask;
|
int alive = (gch(curr)->marked ^ WHITEBITS) & deadmask;
|
||||||
if (gch(curr)->tt == LUA_TTHREAD)
|
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));
|
lua_assert(!isdead(g, curr) || testbit(gch(curr)->marked, FIXEDBIT));
|
||||||
/* in generational mode all live objects are kept black, which
|
/* in generational mode all live objects are kept black, which
|
||||||
means they grow to old generation */
|
means they grow to old generation */
|
||||||
if (gckind != KGC_GEN) makewhite(g, curr);
|
if (gckind != KGC_GEN) makewhitew(white, curr);
|
||||||
p = &gch(curr)->next;
|
p = &gch(curr)->next;
|
||||||
}
|
}
|
||||||
else { /* must erase `curr' */
|
else { /* must erase `curr' */
|
||||||
|
@ -597,8 +600,8 @@ static void checkSizes (lua_State *L) {
|
||||||
static Udata *udata2finalize (global_State *g) {
|
static Udata *udata2finalize (global_State *g) {
|
||||||
GCObject *o = g->tobefnz; /* get first element */
|
GCObject *o = g->tobefnz; /* get first element */
|
||||||
g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */
|
g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */
|
||||||
gch(o)->next = g->rootgc; /* return it to `root' list */
|
gch(o)->next = g->allgc; /* return it to 'allgc' list */
|
||||||
g->rootgc = o;
|
g->allgc = o;
|
||||||
lua_assert(isfinalized(gch(o)));
|
lua_assert(isfinalized(gch(o)));
|
||||||
resetbit(gch(o)->marked, SEPARATED); /* mark it as such */
|
resetbit(gch(o)->marked, SEPARATED); /* mark it as such */
|
||||||
makewhite(g, o);
|
makewhite(g, o);
|
||||||
|
@ -643,7 +646,7 @@ static void GCTM (lua_State *L, int propagateerrors) {
|
||||||
/* move 'dead' udata that need finalization to list 'tobefnz' */
|
/* move 'dead' udata that need finalization to list 'tobefnz' */
|
||||||
void luaC_separateudata (lua_State *L, int all) {
|
void luaC_separateudata (lua_State *L, int all) {
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
GCObject **p = &g->mainthread->next;
|
GCObject **p = &g->udgc;
|
||||||
GCObject *curr;
|
GCObject *curr;
|
||||||
GCObject **lastnext = &g->tobefnz;
|
GCObject **lastnext = &g->tobefnz;
|
||||||
/* find last 'next' field in 'tobefnz' list (to insert elements in its end) */
|
/* 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 */
|
p = &gch(curr)->next; /* don't bother with it */
|
||||||
else {
|
else {
|
||||||
l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */
|
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 */
|
/* link 'curr' at the end of 'tobefnz' list */
|
||||||
gch(curr)->next = *lastnext;
|
gch(curr)->next = *lastnext;
|
||||||
*lastnext = curr;
|
*lastnext = curr;
|
||||||
|
@ -671,13 +674,12 @@ void luaC_checkfinalizer (lua_State *L, Udata *u) {
|
||||||
isfinalized(&u->uv) || /* ... or is finalized... */
|
isfinalized(&u->uv) || /* ... or is finalized... */
|
||||||
gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */
|
gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */
|
||||||
return; /* nothing to be done */
|
return; /* nothing to be done */
|
||||||
else { /* move 'u' to 2nd part of root list */
|
else { /* move 'u' to 'udgc' list */
|
||||||
GCObject **p;
|
GCObject **p;
|
||||||
for (p = &g->rootgc; *p != obj2gco(u); p = &gch(*p)->next)
|
for (p = &g->allgc; *p != obj2gco(u); p = &gch(*p)->next) ;
|
||||||
lua_assert(*p != obj2gco(g->mainthread)); /* 'u' must be in this list */
|
|
||||||
*p = u->uv.next; /* remove 'u' from root list */
|
*p = u->uv.next; /* remove 'u' from root list */
|
||||||
u->uv.next = g->mainthread->next; /* re-link it in list */
|
u->uv.next = g->udgc; /* re-link it in list */
|
||||||
g->mainthread->next = obj2gco(u);
|
g->udgc = obj2gco(u);
|
||||||
l_setbit(u->uv.marked, SEPARATED); /* mark it as such */
|
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 */
|
while (g->tobefnz) GCTM(L, 0); /* Call all pending finalizers */
|
||||||
/* following "white" makes all objects look dead */
|
/* following "white" makes all objects look dead */
|
||||||
g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT);
|
g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT);
|
||||||
sweepwholelist(L, &g->rootgc);
|
sweepwholelist(L, &g->udgc);
|
||||||
lua_assert(g->rootgc == obj2gco(g->mainthread) &&
|
sweepwholelist(L, &g->allgc);
|
||||||
|
lua_assert(g->allgc == obj2gco(g->mainthread) &&
|
||||||
g->mainthread->next == NULL);
|
g->mainthread->next == NULL);
|
||||||
for (i = 0; i < g->strt.size; i++) /* free all string lists */
|
for (i = 0; i < g->strt.size; i++) /* free all string lists */
|
||||||
sweepwholelist(L, &g->strt.hash[i]);
|
sweepwholelist(L, &g->strt.hash[i]);
|
||||||
|
@ -761,19 +764,21 @@ static l_mem singlestep (lua_State *L) {
|
||||||
return GCSWEEPCOST;
|
return GCSWEEPCOST;
|
||||||
}
|
}
|
||||||
else { /* nothing more to sweep */
|
else { /* nothing more to sweep */
|
||||||
g->sweepgc = &g->rootgc;
|
g->sweepgc = &g->udgc; /* sweep all userdata */
|
||||||
g->gcstate = GCSsweep; /* sweep all other objects */
|
g->gcstate = GCSsweepudata;
|
||||||
|
checkSizes(L);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case GCSsweepudata:
|
||||||
case GCSsweep: {
|
case GCSsweep: {
|
||||||
if (*g->sweepgc) {
|
if (*g->sweepgc) {
|
||||||
g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
|
g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
|
||||||
return GCSWEEPMAX*GCSWEEPCOST;
|
return GCSWEEPMAX*GCSWEEPCOST;
|
||||||
}
|
}
|
||||||
else { /* nothing more to sweep */
|
else { /* go to next phase */
|
||||||
checkSizes(L);
|
g->sweepgc = &g->allgc; /* useless (but harmless) in GCSsweep case */
|
||||||
g->gcstate = GCSfinalize; /* end sweep phase */
|
g->gcstate = (g->gcstate == GCSsweep) ? GCSfinalize : GCSsweep;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -856,8 +861,7 @@ void luaC_fullgc (lua_State *L, int isemergency) {
|
||||||
g->gcstate = GCSsweepstring;
|
g->gcstate = GCSsweepstring;
|
||||||
}
|
}
|
||||||
/* finish any pending sweep phase */
|
/* finish any pending sweep phase */
|
||||||
luaC_runtilstate(L, ~bit2mask(GCSsweepstring, GCSsweep));
|
luaC_runtilstate(L, bit2mask(GCSpause, GCSfinalize));
|
||||||
lua_assert(g->gcstate == GCSpause || g->gcstate == GCSfinalize);
|
|
||||||
g->gcstate = GCSpause; /* start a new collection */
|
g->gcstate = GCSpause; /* start a new collection */
|
||||||
/* run collector up to finalizers */
|
/* run collector up to finalizers */
|
||||||
luaC_runtilstate(L, bitmask(GCSfinalize));
|
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
|
** Garbage Collector
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -18,8 +18,9 @@
|
||||||
#define GCSpropagate 1
|
#define GCSpropagate 1
|
||||||
#define GCSatomic 2
|
#define GCSatomic 2
|
||||||
#define GCSsweepstring 3
|
#define GCSsweepstring 3
|
||||||
#define GCSsweep 4
|
#define GCSsweepudata 4
|
||||||
#define GCSfinalize 5
|
#define GCSsweep 5
|
||||||
|
#define GCSfinalize 6
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,12 +46,10 @@
|
||||||
** bit 1 - object is white (type 1)
|
** bit 1 - object is white (type 1)
|
||||||
** bit 2 - object is black
|
** bit 2 - object is black
|
||||||
** bit 3 - for userdata: has been finalized
|
** 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 5 - object is fixed (should not be collected)
|
||||||
** bit 6 - object is "super" fixed (only the main thread)
|
** bit 6 - object is "super" fixed (only the main thread)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#define WHITE0BIT 0
|
#define WHITE0BIT 0
|
||||||
#define WHITE1BIT 1
|
#define WHITE1BIT 1
|
||||||
#define BLACKBIT 2
|
#define BLACKBIT 2
|
||||||
|
@ -58,6 +57,7 @@
|
||||||
#define SEPARATED 4
|
#define SEPARATED 4
|
||||||
#define FIXEDBIT 5
|
#define FIXEDBIT 5
|
||||||
#define SFIXEDBIT 6
|
#define SFIXEDBIT 6
|
||||||
|
|
||||||
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
|
#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
|
** Global State
|
||||||
** See Copyright Notice in lua.h
|
** 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->panic = NULL;
|
||||||
g->version = lua_version(NULL);
|
g->version = lua_version(NULL);
|
||||||
g->gcstate = GCSpause;
|
g->gcstate = GCSpause;
|
||||||
g->rootgc = obj2gco(L);
|
g->allgc = obj2gco(L);
|
||||||
|
g->udgc = NULL;
|
||||||
g->tobefnz = NULL;
|
g->tobefnz = NULL;
|
||||||
g->totalbytes = sizeof(LG);
|
g->totalbytes = sizeof(LG);
|
||||||
g->gcpause = LUAI_GCPAUSE;
|
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
|
** Global State
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
** Some notes about garbage-collected objects: All objects in Lua must
|
** Some notes about garbage-collected objects: All objects in Lua must
|
||||||
** be kept somehow accessible until being freed.
|
** 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.
|
** 'next' of the CommonHeader.
|
||||||
**
|
**
|
||||||
** Strings are kept in several lists headed by the array g->strt.hash.
|
** 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
|
** when traversing the respective threads, but the thread may already be
|
||||||
** dead, while the upvalue is still accessible through closures.)
|
** dead, while the upvalue is still accessible through closures.)
|
||||||
**
|
**
|
||||||
** Userdata with finalizers are kept in the list g->rootgc, but after
|
** Userdata with finalizers are kept in the list g->udgc.
|
||||||
** the mainthread, which should be otherwise the last element in the
|
|
||||||
** list, as it was the first one inserted there.
|
|
||||||
**
|
**
|
||||||
** The list g->tobefnz links all userdata being finalized.
|
** 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 gcstate; /* state of garbage collector */
|
||||||
lu_byte gckind; /* kind of GC running */
|
lu_byte gckind; /* kind of GC running */
|
||||||
int sweepstrgc; /* position of sweep in `strt' */
|
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 **sweepgc; /* current position of sweep */
|
||||||
GCObject *gray; /* list of gray objects */
|
GCObject *gray; /* list of gray objects */
|
||||||
GCObject *grayagain; /* list of objects to be traversed atomically */
|
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
|
** Internal Module for Debugging of the Lua Implementation
|
||||||
** See Copyright Notice in lua.h
|
** 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) {
|
static void printobj (global_State *g, GCObject *o) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
GCObject *p;
|
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;
|
if (p == NULL) i = -1;
|
||||||
printf("%d:%s(%p)-%c(%02X)", i, typename(gch(o)->tt), (void *)o,
|
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);
|
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);
|
checkliveness(g, &g->l_registry);
|
||||||
lua_assert(!isdead(g, obj2gco(g->l_gt)));
|
lua_assert(!isdead(g, obj2gco(g->l_gt)));
|
||||||
checkstack(g, g->mainthread);
|
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)));
|
lua_assert(!testbits(o->gch.marked, bit2mask(SEPARATED, SFIXEDBIT)));
|
||||||
checkobject(g, o);
|
checkobject(g, o);
|
||||||
}
|
}
|
||||||
lua_assert(testbit(o->gch.marked, SFIXEDBIT));
|
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 &&
|
lua_assert(gch(o)->tt == LUA_TUSERDATA &&
|
||||||
!isdead(g, o) &&
|
!isdead(g, o) &&
|
||||||
testbit(o->gch.marked, SEPARATED));
|
testbit(o->gch.marked, SEPARATED));
|
||||||
|
|
Loading…
Reference in New Issue