|
@@ -1,5 +1,5 @@
|
|
/*
|
|
/*
|
|
-** $Id: lgc.c,v 1.185 2003/12/04 17:22:42 roberto Exp roberto $
|
|
|
|
|
|
+** $Id: lgc.c,v 1.186 2003/12/04 18:52:23 roberto Exp roberto $
|
|
** Garbage Collector
|
|
** Garbage Collector
|
|
** See Copyright Notice in lua.h
|
|
** See Copyright Notice in lua.h
|
|
*/
|
|
*/
|
|
@@ -25,12 +25,8 @@
|
|
#define GCSTEPSIZE (20*sizeof(TObject))
|
|
#define GCSTEPSIZE (20*sizeof(TObject))
|
|
|
|
|
|
|
|
|
|
-#define otherwhite(g) (g->currentwhite ^ bit2mask(WHITE0BIT, WHITE1BIT))
|
|
|
|
-
|
|
|
|
-#define isblack(x) testbit((x)->gch.marked, BLACKBIT)
|
|
|
|
#define gray2black(x) setbit((x)->gch.marked, BLACKBIT)
|
|
#define gray2black(x) setbit((x)->gch.marked, BLACKBIT)
|
|
|
|
|
|
-#define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT)
|
|
|
|
#define maskmarks \
|
|
#define maskmarks \
|
|
cast(lu_byte, ~(bitmask(BLACKBIT)|bit2mask(WHITE0BIT, WHITE1BIT)))
|
|
cast(lu_byte, ~(bitmask(BLACKBIT)|bit2mask(WHITE0BIT, WHITE1BIT)))
|
|
#define makewhite(g,x) \
|
|
#define makewhite(g,x) \
|
|
@@ -47,7 +43,6 @@
|
|
#define markfinalized(u) setbit((u)->uv.marked, FINALIZEDBIT)
|
|
#define markfinalized(u) setbit((u)->uv.marked, FINALIZEDBIT)
|
|
|
|
|
|
|
|
|
|
-
|
|
|
|
#define KEYWEAK bitmask(KEYWEAKBIT)
|
|
#define KEYWEAK bitmask(KEYWEAKBIT)
|
|
#define VALUEWEAK bitmask(VALUEWEAKBIT)
|
|
#define VALUEWEAK bitmask(VALUEWEAKBIT)
|
|
|
|
|
|
@@ -110,7 +105,7 @@ static size_t objsize (GCObject *o) {
|
|
|
|
|
|
static void reallymarkobject (global_State *g, GCObject *o) {
|
|
static void reallymarkobject (global_State *g, GCObject *o) {
|
|
lua_assert(iswhite(o));
|
|
lua_assert(iswhite(o));
|
|
- lua_assert(!(o->gch.marked & otherwhite(g)));
|
|
|
|
|
|
+ lua_assert(!isdead(g, o));
|
|
white2gray(o);
|
|
white2gray(o);
|
|
switch (o->gch.tt) {
|
|
switch (o->gch.tt) {
|
|
case LUA_TSTRING: {
|
|
case LUA_TSTRING: {
|
|
@@ -118,6 +113,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
|
|
}
|
|
}
|
|
case LUA_TUSERDATA: {
|
|
case LUA_TUSERDATA: {
|
|
Table *mt = gcotou(o)->uv.metatable;
|
|
Table *mt = gcotou(o)->uv.metatable;
|
|
|
|
+ gray2black(o); /* udata are never gray */
|
|
if (mt) markobject(g, mt);
|
|
if (mt) markobject(g, mt);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
@@ -442,7 +438,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int all,
|
|
int dead = otherwhite(g);
|
|
int dead = otherwhite(g);
|
|
while ((curr = *p) != NULL) {
|
|
while ((curr = *p) != NULL) {
|
|
int mark = curr->gch.marked;
|
|
int mark = curr->gch.marked;
|
|
- lua_assert(all || !(mark & g->currentwhite));
|
|
|
|
lim -= objsize(curr);
|
|
lim -= objsize(curr);
|
|
if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) {
|
|
if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) {
|
|
makewhite(g, curr);
|
|
makewhite(g, curr);
|
|
@@ -469,9 +464,9 @@ static l_mem sweepstrings (lua_State *L, int all, l_mem lim) {
|
|
while ((curr = *p) != NULL) {
|
|
while ((curr = *p) != NULL) {
|
|
int mark = curr->gch.marked;
|
|
int mark = curr->gch.marked;
|
|
lu_mem size = sizestring(gcotots(curr)->tsv.len);
|
|
lu_mem size = sizestring(gcotots(curr)->tsv.len);
|
|
- lua_assert(all || !(mark & g->currentwhite));
|
|
|
|
if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) {
|
|
if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) {
|
|
makewhite(g, curr);
|
|
makewhite(g, curr);
|
|
|
|
+ lua_assert(iswhite(curr) && !isdead(g, curr));
|
|
p = &curr->gch.next;
|
|
p = &curr->gch.next;
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
@@ -499,8 +494,6 @@ static void checkSizes (lua_State *L) {
|
|
size_t newsize = luaZ_sizebuffer(&g->buff) / 2;
|
|
size_t newsize = luaZ_sizebuffer(&g->buff) / 2;
|
|
luaZ_resizebuffer(L, &g->buff, newsize);
|
|
luaZ_resizebuffer(L, &g->buff, newsize);
|
|
}
|
|
}
|
|
- lua_assert(g->nblocks > g->GCthreshold);
|
|
|
|
- g->GCthreshold = 2*G(L)->nblocks - g->GCthreshold; /* new threshold */
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -562,11 +555,13 @@ static void markroot (lua_State *L) {
|
|
|
|
|
|
static void atomic (lua_State *L) {
|
|
static void atomic (lua_State *L) {
|
|
global_State *g = G(L);
|
|
global_State *g = G(L);
|
|
|
|
+ /* there may be some gray elements due to the write barrier */
|
|
|
|
+ propagatemarks(g, MAXLMEM); /* traverse them */
|
|
lua_assert(g->gray == NULL);
|
|
lua_assert(g->gray == NULL);
|
|
g->gray = g->grayagain;
|
|
g->gray = g->grayagain;
|
|
g->grayagain = NULL;
|
|
g->grayagain = NULL;
|
|
propagatemarks(g, MAXLMEM);
|
|
propagatemarks(g, MAXLMEM);
|
|
- g->GCthreshold = luaC_separateudata(L); /* separate userdata to be preserved */
|
|
|
|
|
|
+ luaC_separateudata(L); /* separate userdata to be preserved */
|
|
marktmu(g); /* mark `preserved' userdata */
|
|
marktmu(g); /* mark `preserved' userdata */
|
|
propagatemarks(g, MAXLMEM); /* remark, to propagate `preserveness' */
|
|
propagatemarks(g, MAXLMEM); /* remark, to propagate `preserveness' */
|
|
cleartable(g->weak); /* remove collected objects from weak tables */
|
|
cleartable(g->weak); /* remove collected objects from weak tables */
|
|
@@ -597,30 +592,48 @@ static void sweepstep (lua_State *L) {
|
|
global_State *g = G(L);
|
|
global_State *g = G(L);
|
|
l_mem lim = GCSTEPSIZE;
|
|
l_mem lim = GCSTEPSIZE;
|
|
g->sweepgc = sweeplist(L, g->sweepgc, 0, &lim);
|
|
g->sweepgc = sweeplist(L, g->sweepgc, 0, &lim);
|
|
- if (lim == GCSTEPSIZE) /* nothing more to sweep? */
|
|
|
|
|
|
+ if (lim == GCSTEPSIZE) { /* nothing more to sweep? */
|
|
g->gcstate = GCSfinalize; /* end sweep phase */
|
|
g->gcstate = GCSfinalize; /* end sweep phase */
|
|
|
|
+ checkSizes(L);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-void luaC_collectgarbage (lua_State *L) {
|
|
|
|
|
|
+void luaC_step (lua_State *L) {
|
|
global_State *g = G(L);
|
|
global_State *g = G(L);
|
|
- /* GCSroot */
|
|
|
|
- markroot(L);
|
|
|
|
- /* GCSpropagate */
|
|
|
|
- while (g->gcstate == GCSpropagate)
|
|
|
|
- propagatemarks(g, GCSTEPSIZE);
|
|
|
|
- /* atomic */
|
|
|
|
- atomic(L);
|
|
|
|
- /* GCSsweepstring */
|
|
|
|
- while (g->gcstate == GCSsweepstring)
|
|
|
|
- sweepstringstep(L);
|
|
|
|
- /* GCSsweep */
|
|
|
|
- while (g->gcstate == GCSsweep)
|
|
|
|
- sweepstep(L);
|
|
|
|
- /* GCSfinalize */
|
|
|
|
- checkSizes(L);
|
|
|
|
- while (g->gcstate == GCSfinalize)
|
|
|
|
- GCTM(L);
|
|
|
|
|
|
+ switch (g->gcstate) {
|
|
|
|
+ case GCSroot:
|
|
|
|
+ markroot(L);
|
|
|
|
+ break;
|
|
|
|
+ case GCSpropagate:
|
|
|
|
+ propagatemarks(g, GCSTEPSIZE);
|
|
|
|
+ break;
|
|
|
|
+ case GCSatomic:
|
|
|
|
+ atomic(L);
|
|
|
|
+ break;
|
|
|
|
+ case GCSsweepstring:
|
|
|
|
+ sweepstringstep(L);
|
|
|
|
+ break;
|
|
|
|
+ case GCSsweep:
|
|
|
|
+ sweepstep(L);
|
|
|
|
+ break;
|
|
|
|
+ case GCSfinalize:
|
|
|
|
+ GCTM(L);
|
|
|
|
+ break;
|
|
|
|
+ default: lua_assert(0);
|
|
|
|
+ }
|
|
|
|
+ g->GCthreshold = g->nblocks + GCSTEPSIZE;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
|
|
|
|
+ global_State *g = G(L);
|
|
|
|
+ lua_assert(isblack(o) && iswhite(v));
|
|
|
|
+ lua_assert(!isdead(g, v) && !isdead(g, o));
|
|
|
|
+ if (g->gcstate > GCSatomic) /* sweeping phases? */
|
|
|
|
+ black2gray(o); /* just mark as gray to avoid other barriers */
|
|
|
|
+ else /* breaking invariant! */
|
|
|
|
+ reallymarkobject(g, v); /* restore it */
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|