|
@@ -1,5 +1,5 @@
|
|
/*
|
|
/*
|
|
-** $Id: lgc.c,v 2.2 2003/12/12 18:29:34 roberto Exp roberto $
|
|
|
|
|
|
+** $Id: lgc.c,v 2.3 2004/02/16 19:09:52 roberto Exp roberto $
|
|
** Garbage Collector
|
|
** Garbage Collector
|
|
** See Copyright Notice in lua.h
|
|
** See Copyright Notice in lua.h
|
|
*/
|
|
*/
|
|
@@ -23,6 +23,8 @@
|
|
|
|
|
|
|
|
|
|
#define GCSTEPSIZE (40*sizeof(TValue))
|
|
#define GCSTEPSIZE (40*sizeof(TValue))
|
|
|
|
+#define GCFREECOST (sizeof(TValue)/2)
|
|
|
|
+#define GCSWEEPCOST sizeof(TValue)
|
|
|
|
|
|
|
|
|
|
#define gray2black(x) setbit((x)->gch.marked, BLACKBIT)
|
|
#define gray2black(x) setbit((x)->gch.marked, BLACKBIT)
|
|
@@ -51,10 +53,6 @@
|
|
#define markvalue(g,o) { checkconsistency(o); \
|
|
#define markvalue(g,o) { checkconsistency(o); \
|
|
if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); }
|
|
if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); }
|
|
|
|
|
|
-#define condmarkobject(g,o,c) { checkconsistency(o); \
|
|
|
|
- if (iscollectable(o) && iswhite(gcvalue(o)) && (c)) \
|
|
|
|
- reallymarkobject(g,gcvalue(o)); }
|
|
|
|
-
|
|
|
|
#define markobject(g,t) { if (iswhite(obj2gco(t))) \
|
|
#define markobject(g,t) { if (iswhite(obj2gco(t))) \
|
|
reallymarkobject(g, obj2gco(t)); }
|
|
reallymarkobject(g, obj2gco(t)); }
|
|
|
|
|
|
@@ -214,8 +212,8 @@ static int traversetable (global_State *g, Table *h) {
|
|
Node *n = gnode(h, i);
|
|
Node *n = gnode(h, i);
|
|
if (!ttisnil(gval(n))) {
|
|
if (!ttisnil(gval(n))) {
|
|
lua_assert(!ttisnil(gkey(n)));
|
|
lua_assert(!ttisnil(gkey(n)));
|
|
- condmarkobject(g, gkey(n), !weakkey);
|
|
|
|
- condmarkobject(g, gval(n), !weakvalue);
|
|
|
|
|
|
+ if (!weakkey) markvalue(g, gkey(n));
|
|
|
|
+ if (!weakvalue) markvalue(g, gval(n));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return weakkey || weakvalue;
|
|
return weakkey || weakvalue;
|
|
@@ -444,18 +442,19 @@ 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;
|
|
- lim -= objsize(curr);
|
|
|
|
if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) {
|
|
if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) {
|
|
makewhite(g, curr);
|
|
makewhite(g, curr);
|
|
if (curr->gch.tt == LUA_TTHREAD)
|
|
if (curr->gch.tt == LUA_TTHREAD)
|
|
sweepupvalues(g, gco2th(curr));
|
|
sweepupvalues(g, gco2th(curr));
|
|
p = &curr->gch.next;
|
|
p = &curr->gch.next;
|
|
|
|
+ lim -= GCSWEEPCOST;
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
*p = curr->gch.next;
|
|
*p = curr->gch.next;
|
|
if (curr == g->rootgc) /* is the first element of the list? */
|
|
if (curr == g->rootgc) /* is the first element of the list? */
|
|
g->rootgc = curr->gch.next; /* adjust first */
|
|
g->rootgc = curr->gch.next; /* adjust first */
|
|
freeobj(L, curr);
|
|
freeobj(L, curr);
|
|
|
|
+ lim -= GCFREECOST;
|
|
}
|
|
}
|
|
if (lim <= 0) break;
|
|
if (lim <= 0) break;
|
|
}
|
|
}
|
|
@@ -583,19 +582,16 @@ static void atomic (lua_State *L) {
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-void luaC_step (lua_State *L) {
|
|
|
|
|
|
+static l_mem singlestep (lua_State *L, l_mem lim) {
|
|
global_State *g = G(L);
|
|
global_State *g = G(L);
|
|
- l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * 2;
|
|
|
|
-luaC_checkall(L);
|
|
|
|
switch (g->gcstate) {
|
|
switch (g->gcstate) {
|
|
case GCSpropagate: {
|
|
case GCSpropagate: {
|
|
if (g->gray)
|
|
if (g->gray)
|
|
- lim = propagatemarks(g, lim);
|
|
|
|
|
|
+ return propagatemarks(g, lim);
|
|
else { /* no more `gray' objects */
|
|
else { /* no more `gray' objects */
|
|
atomic(L); /* finish mark phase */
|
|
atomic(L); /* finish mark phase */
|
|
- lim = 0;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
- break;
|
|
|
|
}
|
|
}
|
|
case GCSsweepstring: {
|
|
case GCSsweepstring: {
|
|
lim = sweepstrings(L, 0, lim);
|
|
lim = sweepstrings(L, 0, lim);
|
|
@@ -603,7 +599,7 @@ luaC_checkall(L);
|
|
g->sweepstrgc = 0;
|
|
g->sweepstrgc = 0;
|
|
g->gcstate = GCSsweep; /* end sweep-string phase */
|
|
g->gcstate = GCSsweep; /* end sweep-string phase */
|
|
}
|
|
}
|
|
- break;
|
|
|
|
|
|
+ return lim;
|
|
}
|
|
}
|
|
case GCSsweep: {
|
|
case GCSsweep: {
|
|
g->sweepgc = sweeplist(L, g->sweepgc, 0, &lim);
|
|
g->sweepgc = sweeplist(L, g->sweepgc, 0, &lim);
|
|
@@ -612,27 +608,45 @@ luaC_checkall(L);
|
|
sweepupvalues(g, g->mainthread);
|
|
sweepupvalues(g, g->mainthread);
|
|
g->gcstate = GCSfinalize; /* end sweep phase */
|
|
g->gcstate = GCSfinalize; /* end sweep phase */
|
|
}
|
|
}
|
|
- break;
|
|
|
|
|
|
+ return lim;
|
|
}
|
|
}
|
|
case GCSfinalize: {
|
|
case GCSfinalize: {
|
|
- if (g->tmudata) {
|
|
|
|
|
|
+ if (g->tmudata)
|
|
GCTM(L);
|
|
GCTM(L);
|
|
- lim = 0;
|
|
|
|
- }
|
|
|
|
else /* no more `udata' to finalize */
|
|
else /* no more `udata' to finalize */
|
|
markroot(L); /* may restart collection */
|
|
markroot(L); /* may restart collection */
|
|
- break;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
- default: lua_assert(0);
|
|
|
|
|
|
+ default: lua_assert(0); return 0; /* to avoid warnings */
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+void luaC_step (lua_State *L) {
|
|
|
|
+ global_State *g = G(L);
|
|
|
|
+ l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * 2;
|
|
|
|
+/*printf("+ %d %lu %lu %ld\n", g->gcstate, g->nblocks, g->GCthreshold, lim);*/
|
|
|
|
+ while (lim > 0) lim = singlestep(L, lim);
|
|
g->GCthreshold = g->nblocks + GCSTEPSIZE - lim/2;
|
|
g->GCthreshold = g->nblocks + GCSTEPSIZE - lim/2;
|
|
-luaC_checkall(L);
|
|
|
|
|
|
+/*printf("- %d %lu %lu %ld\n", g->gcstate, g->nblocks, g->GCthreshold, lim);*/
|
|
|
|
+ lua_assert((long)g->nblocks + (long)GCSTEPSIZE >= lim/2);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+void luaC_fullgc (lua_State *L) {
|
|
|
|
+ global_State *g = G(L);
|
|
|
|
+ while (g->gcstate != GCSfinalize) singlestep(L, MAXLMEM);
|
|
|
|
+ markroot(L);
|
|
|
|
+ while (g->gcstate != GCSfinalize) singlestep(L, MAXLMEM);
|
|
|
|
+ luaC_callGCTM(L); /* call finalizers */
|
|
|
|
+ g->GCthreshold = g->nblocks + GCSTEPSIZE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
|
|
void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
|
|
global_State *g = G(L);
|
|
global_State *g = G(L);
|
|
lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
|
|
lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
|
|
|
|
+ lua_assert(g->gcstate != GCSfinalize);
|
|
if (g->gcstate != GCSpropagate) /* sweeping phases? */
|
|
if (g->gcstate != GCSpropagate) /* sweeping phases? */
|
|
black2gray(o); /* just mark as gray to avoid other barriers */
|
|
black2gray(o); /* just mark as gray to avoid other barriers */
|
|
else /* breaking invariant! */
|
|
else /* breaking invariant! */
|