aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2003-05-16 15:58:39 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2003-05-16 15:58:39 -0300
commitecf5730c0cc2dde4006a0dded0cf3dd241636cba (patch)
tree181c79999d42333dffbcb1a914c7bffc7beeb8e5
parentb10bfd4934aafe57b29def11ad56e0e7bb39a564 (diff)
downloadlua-ecf5730c0cc2dde4006a0dded0cf3dd241636cba.tar.gz
lua-ecf5730c0cc2dde4006a0dded0cf3dd241636cba.tar.bz2
lua-ecf5730c0cc2dde4006a0dded0cf3dd241636cba.zip
(much) smarter way to clear weak tables
-rw-r--r--lgc.c94
1 files changed, 37 insertions, 57 deletions
diff --git a/lgc.c b/lgc.c
index 4101dd6d..6f9a7559 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.c,v 1.171 2003/04/03 13:35:34 roberto Exp roberto $ 2** $Id: lgc.c,v 1.172 2003/04/28 19:26:16 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*/
@@ -24,9 +24,7 @@
24 24
25typedef struct GCState { 25typedef struct GCState {
26 GCObject *tmark; /* list of marked objects to be traversed */ 26 GCObject *tmark; /* list of marked objects to be traversed */
27 GCObject *wk; /* list of traversed key-weak tables (to be cleared) */ 27 GCObject *w; /* list of traversed weak tables (to be cleared) */
28 GCObject *wv; /* list of traversed value-weak tables */
29 GCObject *wkv; /* list of traversed key-value weak tables */
30 global_State *g; 28 global_State *g;
31} GCState; 29} GCState;
32 30
@@ -125,6 +123,7 @@ void luaC_separateudata (lua_State *L) {
125 p = &curr->gch.next; 123 p = &curr->gch.next;
126 } 124 }
127 else { /* must call its gc method */ 125 else { /* must call its gc method */
126 markfinalized(gcotou(curr));
128 *p = curr->gch.next; 127 *p = curr->gch.next;
129 curr->gch.next = NULL; /* link `curr' at the end of `collected' list */ 128 curr->gch.next = NULL; /* link `curr' at the end of `collected' list */
130 *lastcollected = curr; 129 *lastcollected = curr;
@@ -137,13 +136,6 @@ void luaC_separateudata (lua_State *L) {
137} 136}
138 137
139 138
140static void removekey (Node *n) {
141 setnilvalue(gval(n)); /* remove corresponding value ... */
142 if (iscollectable(gkey(n)))
143 setttype(gkey(n), LUA_TNONE); /* dead key; remove it */
144}
145
146
147static void traversetable (GCState *st, Table *h) { 139static void traversetable (GCState *st, Table *h) {
148 int i; 140 int i;
149 int weakkey = 0; 141 int weakkey = 0;
@@ -156,17 +148,14 @@ static void traversetable (GCState *st, Table *h) {
156 weakkey = (strchr(svalue(mode), 'k') != NULL); 148 weakkey = (strchr(svalue(mode), 'k') != NULL);
157 weakvalue = (strchr(svalue(mode), 'v') != NULL); 149 weakvalue = (strchr(svalue(mode), 'v') != NULL);
158 if (weakkey || weakvalue) { /* is really weak? */ 150 if (weakkey || weakvalue) { /* is really weak? */
159 GCObject **weaklist;
160 h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ 151 h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */
161 h->marked |= cast(lu_byte, (weakkey << KEYWEAKBIT) | 152 h->marked |= cast(lu_byte, (weakkey << KEYWEAKBIT) |
162 (weakvalue << VALUEWEAKBIT)); 153 (weakvalue << VALUEWEAKBIT));
163 weaklist = (weakkey && weakvalue) ? &st->wkv : 154 h->gclist = st->w; /* must be cleared after GC, ... */
164 (weakkey) ? &st->wk : 155 st->w = valtogco(h); /* ... so put in the appropriate list */
165 &st->wv;
166 h->gclist = *weaklist; /* must be cleared after GC, ... */
167 *weaklist = valtogco(h); /* ... so put in the appropriate list */
168 } 156 }
169 } 157 }
158 if (weakkey && weakvalue) return;
170 if (!weakvalue) { 159 if (!weakvalue) {
171 i = h->sizearray; 160 i = h->sizearray;
172 while (i--) 161 while (i--)
@@ -288,48 +277,51 @@ static void propagatemarks (GCState *st) {
288} 277}
289 278
290 279
291static int valismarked (const TObject *o) { 280/*
292 if (ttisstring(o)) 281** The next function tells whether a key or value can be cleared from
282** a weak table. Non-collectable objects are never removed from weak
283** tables. Strings behave as `values', so are never removed too. for
284** other objects: if really collected, cannot keep them; for userdata
285** being finalized, keep them in keys, but not in values
286*/
287static int iscleared (const TObject *o, int iskey) {
288 if (!iscollectable(o)) return 0;
289 if (ttisstring(o)) {
293 stringmark(tsvalue(o)); /* strings are `values', so are never weak */ 290 stringmark(tsvalue(o)); /* strings are `values', so are never weak */
294 return !iscollectable(o) || testbit(o->value.gc->gch.marked, 0); 291 return 0;
292 }
293 return !ismarked(gcvalue(o)) ||
294 (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o))));
295} 295}
296 296
297 297
298/* 298static void removekey (Node *n) {
299** clear collected keys from weaktables 299 setnilvalue(gval(n)); /* remove corresponding value ... */
300*/ 300 if (iscollectable(gkey(n)))
301static void cleartablekeys (GCObject *l) { 301 setttype(gkey(n), LUA_TNONE); /* dead key; remove it */
302 while (l) {
303 Table *h = gcotoh(l);
304 int i = sizenode(h);
305 lua_assert(h->marked & KEYWEAK);
306 while (i--) {
307 Node *n = gnode(h, i);
308 if (!valismarked(gkey(n))) /* key was collected? */
309 removekey(n); /* remove entry from table */
310 }
311 l = h->gclist;
312 }
313} 302}
314 303
315 304
316/* 305/*
317** clear collected values from weaktables 306** clear collected entries from weaktables
318*/ 307*/
319static void cleartablevalues (GCObject *l) { 308static void cleartable (GCObject *l) {
320 while (l) { 309 while (l) {
321 Table *h = gcotoh(l); 310 Table *h = gcotoh(l);
322 int i = h->sizearray; 311 int i = h->sizearray;
323 lua_assert(h->marked & VALUEWEAK); 312 lua_assert(h->marked & (KEYWEAK | VALUEWEAK));
324 while (i--) { 313 if (h->marked & VALUEWEAK) {
325 TObject *o = &h->array[i]; 314 while (i--) {
326 if (!valismarked(o)) /* value was collected? */ 315 TObject *o = &h->array[i];
327 setnilvalue(o); /* remove value */ 316 if (iscleared(o, 0)) /* value was collected? */
317 setnilvalue(o); /* remove value */
318 }
328 } 319 }
329 i = sizenode(h); 320 i = sizenode(h);
330 while (i--) { 321 while (i--) {
331 Node *n = gnode(h, i); 322 Node *n = gnode(h, i);
332 if (!valismarked(gval(n))) /* value was collected? */ 323 if (!ttisnil(gval(n)) && /* non-empty entry? */
324 (iscleared(gkey(n), 1) || iscleared(gval(n), 0)))
333 removekey(n); /* remove entry from table */ 325 removekey(n); /* remove entry from table */
334 } 326 }
335 l = h->gclist; 327 l = h->gclist;
@@ -424,7 +416,6 @@ void luaC_callGCTM (lua_State *L) {
424 G(L)->rootudata = o; 416 G(L)->rootudata = o;
425 setuvalue(L->top - 1, udata); /* keep a reference to it */ 417 setuvalue(L->top - 1, udata); /* keep a reference to it */
426 unmark(o); 418 unmark(o);
427 markfinalized(udata);
428 do1gcTM(L, udata); 419 do1gcTM(L, udata);
429 } 420 }
430 L->top--; 421 L->top--;
@@ -453,26 +444,15 @@ static void markroot (GCState *st, lua_State *L) {
453 444
454static void mark (lua_State *L) { 445static void mark (lua_State *L) {
455 GCState st; 446 GCState st;
456 GCObject *wkv;
457 st.g = G(L); 447 st.g = G(L);
458 st.tmark = NULL; 448 st.tmark = NULL;
459 st.wkv = st.wk = st.wv = NULL; 449 st.w = NULL;
460 markroot(&st, L); 450 markroot(&st, L);
461 propagatemarks(&st); /* mark all reachable objects */ 451 propagatemarks(&st); /* mark all reachable objects */
462 cleartablevalues(st.wkv);
463 cleartablevalues(st.wv);
464 wkv = st.wkv; /* keys must be cleared after preserving udata */
465 st.wkv = NULL;
466 st.wv = NULL;
467 luaC_separateudata(L); /* separate userdata to be preserved */ 452 luaC_separateudata(L); /* separate userdata to be preserved */
468 marktmu(&st); /* mark `preserved' userdata */ 453 marktmu(&st); /* mark `preserved' userdata */
469 propagatemarks(&st); /* remark, to propagate `preserveness' */ 454 propagatemarks(&st); /* remark, to propagate `preserveness' */
470 cleartablekeys(wkv); 455 cleartable(st.w); /* remove collected objects from weak tables */
471 /* `propagatemarks' may resuscitate some weak tables; clear them too */
472 cleartablekeys(st.wk);
473 cleartablevalues(st.wv);
474 cleartablekeys(st.wkv);
475 cleartablevalues(st.wkv);
476} 456}
477 457
478 458