avoid traversing extra elements when cleaning weak tables

This commit is contained in:
Roberto Ierusalimschy 2002-11-11 09:52:43 -02:00
parent 81e142fc14
commit ac27b7a842

73
lgc.c
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lgc.c,v 1.154 2002/10/25 20:05:28 roberto Exp roberto $ ** $Id: lgc.c,v 1.155 2002/11/07 15:37:10 roberto Exp roberto $
** Garbage Collector ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -22,7 +22,9 @@
typedef struct GCState { typedef struct GCState {
Table *tmark; /* list of marked tables to be visited */ Table *tmark; /* list of marked tables to be visited */
Table *toclear; /* list of visited weak tables (to be cleared after GC) */ Table *wk; /* list of visited key-weak tables (to be cleared after GC) */
Table *wv; /* list of visited value-weak tables */
Table *wkv; /* list of visited key-value weak tables */
lua_State *L; lua_State *L;
} GCState; } GCState;
@ -198,10 +200,14 @@ static void traversetable (GCState *st, Table *h) {
marktable(st, h->metatable); marktable(st, h->metatable);
lua_assert(h->lsizenode || h->node == G(st->L)->dummynode); lua_assert(h->lsizenode || h->node == G(st->L)->dummynode);
if (h->mode & (WEAKKEY | WEAKVALUE)) { /* weak table? */ if (h->mode & (WEAKKEY | WEAKVALUE)) { /* weak table? */
Table **weaklist;
weakkey = h->mode & WEAKKEY; weakkey = h->mode & WEAKKEY;
weakvalue = h->mode & WEAKVALUE; weakvalue = h->mode & WEAKVALUE;
h->gclist = st->toclear; /* must be cleared after GC, ... */ weaklist = (weakkey && weakvalue) ? &st->wkv :
st->toclear = h; /* ... so put in the appropriate list */ (weakkey) ? &st->wk :
&st->wv;
h->gclist = *weaklist; /* must be cleared after GC, ... */
*weaklist = h; /* ... so put in the appropriate list */
} }
if (!weakvalue) { if (!weakvalue) {
i = sizearray(h); i = sizearray(h);
@ -241,14 +247,12 @@ static int valismarked (const TObject *o) {
*/ */
static void cleartablekeys (Table *h) { static void cleartablekeys (Table *h) {
for (; h; h = h->gclist) { for (; h; h = h->gclist) {
lua_assert(h->mode & (WEAKKEY | WEAKVALUE)); int i = sizenode(h);
if ((h->mode & WEAKKEY)) { /* table may have collected keys? */ lua_assert(h->mode & WEAKKEY);
int i = sizenode(h); while (i--) {
while (i--) { Node *n = node(h, i);
Node *n = node(h, i); if (!valismarked(key(n))) /* key was collected? */
if (!valismarked(key(n))) /* key was collected? */ removekey(n); /* remove entry from table */
removekey(n); /* remove entry from table */
}
} }
} }
} }
@ -259,19 +263,18 @@ static void cleartablekeys (Table *h) {
*/ */
static void cleartablevalues (Table *h) { static void cleartablevalues (Table *h) {
for (; h; h = h->gclist) { for (; h; h = h->gclist) {
if ((h->mode & WEAKVALUE)) { /* table may have collected values? */ int i = sizearray(h);
int i = sizearray(h); lua_assert(h->mode & WEAKVALUE);
while (i--) { while (i--) {
TObject *o = &h->array[i]; TObject *o = &h->array[i];
if (!valismarked(o)) /* value was collected? */ if (!valismarked(o)) /* value was collected? */
setnilvalue(o); /* remove value */ setnilvalue(o); /* remove value */
} }
i = sizenode(h); i = sizenode(h);
while (i--) { while (i--) {
Node *n = node(h, i); Node *n = node(h, i);
if (!valismarked(val(n))) /* value was collected? */ if (!valismarked(val(n))) /* value was collected? */
removekey(n); /* remove entry from table */ removekey(n); /* remove entry from table */
}
} }
} }
} }
@ -398,22 +401,26 @@ static void markroot (GCState *st) {
static void mark (lua_State *L) { static void mark (lua_State *L) {
GCState st; GCState st;
Table *toclear; Table *wkv;
st.L = L; st.L = L;
st.tmark = NULL; st.tmark = NULL;
st.toclear = NULL; st.wkv = st.wk = st.wv = NULL;
markroot(&st); markroot(&st);
propagatemarks(&st); /* mark all reachable objects */ propagatemarks(&st); /* mark all reachable objects */
toclear = st.toclear; /* weak tables; to be cleared */ cleartablevalues(st.wkv);
st.toclear = NULL; cleartablevalues(st.wv);
cleartablevalues(toclear); wkv = st.wkv; /* keys must be cleared after preserving udata */
st.wkv = NULL;
st.wv = NULL;
separateudata(L); /* separate userdata to be preserved */ separateudata(L); /* separate userdata to be preserved */
marktmu(&st); /* mark `preserved' userdata */ marktmu(&st); /* mark `preserved' userdata */
propagatemarks(&st); /* remark, to propagate `preserveness' */ propagatemarks(&st); /* remark, to propagate `preserveness' */
cleartablekeys(toclear); cleartablekeys(wkv);
/* `propagatemarks' may reborne some weak tables; clear them too */ /* `propagatemarks' may reborne some weak tables; clear them too */
cleartablekeys(st.toclear); cleartablekeys(st.wk);
cleartablevalues(st.toclear); cleartablevalues(st.wv);
cleartablekeys(st.wkv);
cleartablevalues(st.wkv);
} }