aboutsummaryrefslogtreecommitdiff
path: root/lgc.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2002-07-01 14:06:58 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2002-07-01 14:06:58 -0300
commit9f4b5b52327497e3ce82cb0af1d94ad6c09b1da2 (patch)
tree748e3f7b84f04d7ab438b9970ac42ef0efe95811 /lgc.c
parent5fabed21a17b133182a7e47712b7c7602ea87401 (diff)
downloadlua-9f4b5b52327497e3ce82cb0af1d94ad6c09b1da2.tar.gz
lua-9f4b5b52327497e3ce82cb0af1d94ad6c09b1da2.tar.bz2
lua-9f4b5b52327497e3ce82cb0af1d94ad6c09b1da2.zip
weak keys are removed only after finalization
Diffstat (limited to 'lgc.c')
-rw-r--r--lgc.c54
1 files changed, 44 insertions, 10 deletions
diff --git a/lgc.c b/lgc.c
index c7429c26..e5ecb9c6 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.c,v 1.138 2002/06/24 17:19:43 roberto Exp roberto $ 2** $Id: lgc.c,v 1.139 2002/06/25 19:17:42 roberto Exp roberto $
3** Garbage Collector 3** Garbage Collector
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -31,6 +31,17 @@ typedef struct GCState {
31#define strmark(s) {if ((s)->tsv.marked == 0) (s)->tsv.marked = 1;} 31#define strmark(s) {if ((s)->tsv.marked == 0) (s)->tsv.marked = 1;}
32 32
33 33
34/* unmarked tables are represented by pointing `mark' to themselves */
35#define ismarked(x) ((x)->mark != (x))
36
37
38/* `Table.flag' bits to indicate whether table is key-weak and/or value-weak */
39#define KEYWEAKBIT (TM_MODE+1) /* ORDER TM */
40#define VALUEWEAKBIT (TM_MODE+2)
41#define KEYWEAK (1<<KEYWEAKBIT)
42#define VALUEWEAK (1<<VALUEWEAKBIT)
43
44
34/* mark tricks for userdata */ 45/* mark tricks for userdata */
35#define isudmarked(u) (u->uv.len & 1) 46#define isudmarked(u) (u->uv.len & 1)
36#define markud(u) (u->uv.len |= 1) 47#define markud(u) (u->uv.len |= 1)
@@ -202,8 +213,8 @@ static void separateudata (lua_State *L) {
202 213
203 214
204static void removekey (Node *n) { 215static void removekey (Node *n) {
205 lua_assert(ttype(val(n)) == LUA_TNIL); 216 setnilvalue(val(n)); /* remove corresponding value ... */
206 if (ttype(key(n)) != LUA_TNIL && ttype(key(n)) != LUA_TNUMBER) 217 if (ismarkable(key(n)))
207 setttype(key(n), LUA_TNONE); /* dead key; remove it */ 218 setttype(key(n), LUA_TNONE); /* dead key; remove it */
208} 219}
209 220
@@ -221,6 +232,8 @@ static void traversetable (GCState *st, Table *h) {
221 st->toclear = h; /* ...put in the appropriate list */ 232 st->toclear = h; /* ...put in the appropriate list */
222 weakkey = (strchr(svalue(mode), 'k') != NULL); 233 weakkey = (strchr(svalue(mode), 'k') != NULL);
223 weakvalue = (strchr(svalue(mode), 'v') != NULL); 234 weakvalue = (strchr(svalue(mode), 'v') != NULL);
235 h->flags &= ~(KEYWEAK | VALUEWEAK); /* clear bits */
236 h->flags |= (weakkey << KEYWEAKBIT) | (weakvalue << VALUEWEAKBIT);
224 } 237 }
225 if (!weakvalue) { 238 if (!weakvalue) {
226 i = sizearray(h); 239 i = sizearray(h);
@@ -265,11 +278,33 @@ static int hasmark (const TObject *o) {
265 278
266 279
267/* 280/*
268** clear (set to nil) keys and values from weaktables that were collected 281** clear collected keys from weaktables
269*/ 282*/
270static void cleartables (Table *h) { 283static void cleartablekeys (GCState *st) {
271 for (; h; h = h->mark) { 284 Table *h;
285 for (h = st->toclear; h; h = h->mark) {
272 int i; 286 int i;
287 if (!(h->flags & KEYWEAK)) continue;
288 lua_assert(strchr(svalue(fasttm(st->L, h->metatable, TM_MODE)), 'k'));
289 i = sizenode(h);
290 while (i--) {
291 Node *n = node(h, i);
292 if (!hasmark(key(n)))
293 removekey(n); /* ... and key */
294 }
295 }
296}
297
298
299/*
300** clear collected values from weaktables
301*/
302static void cleartablevalues (GCState *st) {
303 Table *h;
304 for (h = st->toclear; h; h = h->mark) {
305 int i;
306 if (!(h->flags & VALUEWEAK)) continue;
307 lua_assert(strchr(svalue(fasttm(st->L, h->metatable, TM_MODE)), 'v'));
273 i = sizearray(h); 308 i = sizearray(h);
274 while (i--) { 309 while (i--) {
275 TObject *o = &h->array[i]; 310 TObject *o = &h->array[i];
@@ -279,10 +314,8 @@ static void cleartables (Table *h) {
279 i = sizenode(h); 314 i = sizenode(h);
280 while (i--) { 315 while (i--) {
281 Node *n = node(h, i); 316 Node *n = node(h, i);
282 if (!hasmark(val(n)) || !hasmark(key(n))) { 317 if (!hasmark(val(n)))
283 setnilvalue(val(n)); /* remove value ... */
284 removekey(n); /* ... and key */ 318 removekey(n); /* ... and key */
285 }
286 } 319 }
287 } 320 }
288} 321}
@@ -458,10 +491,11 @@ void luaC_collectgarbage (lua_State *L) {
458 st.toclear = NULL; 491 st.toclear = NULL;
459 markstacks(&st); /* mark all stacks */ 492 markstacks(&st); /* mark all stacks */
460 propagatemarks(&st); /* mark all reachable objects */ 493 propagatemarks(&st); /* mark all reachable objects */
461 cleartables(st.toclear); 494 cleartablevalues(&st);
462 separateudata(L); /* separate userdata to be preserved */ 495 separateudata(L); /* separate userdata to be preserved */
463 marktmu(&st); /* mark `preserved' userdata */ 496 marktmu(&st); /* mark `preserved' userdata */
464 propagatemarks(&st); /* remark */ 497 propagatemarks(&st); /* remark */
498 cleartablekeys(&st);
465 luaC_collect(L, 0); 499 luaC_collect(L, 0);
466 checkMbuffer(L); 500 checkMbuffer(L);
467 G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */ 501 G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */