weak keys are removed only after finalization

This commit is contained in:
Roberto Ierusalimschy
2002-07-01 14:06:58 -03:00
parent 5fabed21a1
commit 9f4b5b5232
3 changed files with 53 additions and 15 deletions

54
lgc.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lgc.c,v 1.138 2002/06/24 17:19:43 roberto Exp roberto $ ** $Id: lgc.c,v 1.139 2002/06/25 19:17:42 roberto Exp roberto $
** Garbage Collector ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -31,6 +31,17 @@ typedef struct GCState {
#define strmark(s) {if ((s)->tsv.marked == 0) (s)->tsv.marked = 1;} #define strmark(s) {if ((s)->tsv.marked == 0) (s)->tsv.marked = 1;}
/* unmarked tables are represented by pointing `mark' to themselves */
#define ismarked(x) ((x)->mark != (x))
/* `Table.flag' bits to indicate whether table is key-weak and/or value-weak */
#define KEYWEAKBIT (TM_MODE+1) /* ORDER TM */
#define VALUEWEAKBIT (TM_MODE+2)
#define KEYWEAK (1<<KEYWEAKBIT)
#define VALUEWEAK (1<<VALUEWEAKBIT)
/* mark tricks for userdata */ /* mark tricks for userdata */
#define isudmarked(u) (u->uv.len & 1) #define isudmarked(u) (u->uv.len & 1)
#define markud(u) (u->uv.len |= 1) #define markud(u) (u->uv.len |= 1)
@@ -202,8 +213,8 @@ static void separateudata (lua_State *L) {
static void removekey (Node *n) { static void removekey (Node *n) {
lua_assert(ttype(val(n)) == LUA_TNIL); setnilvalue(val(n)); /* remove corresponding value ... */
if (ttype(key(n)) != LUA_TNIL && ttype(key(n)) != LUA_TNUMBER) if (ismarkable(key(n)))
setttype(key(n), LUA_TNONE); /* dead key; remove it */ setttype(key(n), LUA_TNONE); /* dead key; remove it */
} }
@@ -221,6 +232,8 @@ static void traversetable (GCState *st, Table *h) {
st->toclear = h; /* ...put in the appropriate list */ st->toclear = h; /* ...put in the appropriate list */
weakkey = (strchr(svalue(mode), 'k') != NULL); weakkey = (strchr(svalue(mode), 'k') != NULL);
weakvalue = (strchr(svalue(mode), 'v') != NULL); weakvalue = (strchr(svalue(mode), 'v') != NULL);
h->flags &= ~(KEYWEAK | VALUEWEAK); /* clear bits */
h->flags |= (weakkey << KEYWEAKBIT) | (weakvalue << VALUEWEAKBIT);
} }
if (!weakvalue) { if (!weakvalue) {
i = sizearray(h); i = sizearray(h);
@@ -265,11 +278,33 @@ static int hasmark (const TObject *o) {
/* /*
** clear (set to nil) keys and values from weaktables that were collected ** clear collected keys from weaktables
*/ */
static void cleartables (Table *h) { static void cleartablekeys (GCState *st) {
for (; h; h = h->mark) { Table *h;
for (h = st->toclear; h; h = h->mark) {
int i; int i;
if (!(h->flags & KEYWEAK)) continue;
lua_assert(strchr(svalue(fasttm(st->L, h->metatable, TM_MODE)), 'k'));
i = sizenode(h);
while (i--) {
Node *n = node(h, i);
if (!hasmark(key(n)))
removekey(n); /* ... and key */
}
}
}
/*
** clear collected values from weaktables
*/
static void cleartablevalues (GCState *st) {
Table *h;
for (h = st->toclear; h; h = h->mark) {
int i;
if (!(h->flags & VALUEWEAK)) continue;
lua_assert(strchr(svalue(fasttm(st->L, h->metatable, TM_MODE)), 'v'));
i = sizearray(h); i = sizearray(h);
while (i--) { while (i--) {
TObject *o = &h->array[i]; TObject *o = &h->array[i];
@@ -279,13 +314,11 @@ static void cleartables (Table *h) {
i = sizenode(h); i = sizenode(h);
while (i--) { while (i--) {
Node *n = node(h, i); Node *n = node(h, i);
if (!hasmark(val(n)) || !hasmark(key(n))) { if (!hasmark(val(n)))
setnilvalue(val(n)); /* remove value ... */
removekey(n); /* ... and key */ removekey(n); /* ... and key */
} }
} }
} }
}
static void collectproto (lua_State *L) { static void collectproto (lua_State *L) {
@@ -458,10 +491,11 @@ void luaC_collectgarbage (lua_State *L) {
st.toclear = NULL; st.toclear = NULL;
markstacks(&st); /* mark all stacks */ markstacks(&st); /* mark all stacks */
propagatemarks(&st); /* mark all reachable objects */ propagatemarks(&st); /* mark all reachable objects */
cleartables(st.toclear); cleartablevalues(&st);
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 */ propagatemarks(&st); /* remark */
cleartablekeys(&st);
luaC_collect(L, 0); luaC_collect(L, 0);
checkMbuffer(L); checkMbuffer(L);
G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */ G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lobject.h,v 1.137 2002/06/24 13:08:45 roberto Exp roberto $ ** $Id: lobject.h,v 1.138 2002/06/24 20:17:59 roberto Exp roberto $
** Type definitions for Lua objects ** Type definitions for Lua objects
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -217,9 +217,6 @@ typedef struct Table {
} Table; } Table;
/* unmarked tables are represented by pointing `mark' to themselves */
#define ismarked(x) ((x)->mark != (x))
/* /*
** `module' operation for hashing (size is always a power of 2) ** `module' operation for hashing (size is always a power of 2)

9
ltm.h
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: ltm.h,v 1.36 2002/06/24 20:17:59 roberto Exp roberto $ ** $Id: ltm.h,v 1.37 2002/06/25 19:17:22 roberto Exp roberto $
** Tag methods ** Tag methods
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -10,6 +10,13 @@
#include "lobject.h" #include "lobject.h"
/*
** Important: garbage collection uses two extra bits of `Table.flags'
** (after TM_MODE), so the maximum number of `fast tag methods' is six
** (at least while `flags' is a byte).
*/
/* /*
* WARNING: if you change the order of this enumeration, * WARNING: if you change the order of this enumeration,
* grep "ORDER TM" * grep "ORDER TM"