diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2003-05-16 15:58:39 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2003-05-16 15:58:39 -0300 |
| commit | ecf5730c0cc2dde4006a0dded0cf3dd241636cba (patch) | |
| tree | 181c79999d42333dffbcb1a914c7bffc7beeb8e5 | |
| parent | b10bfd4934aafe57b29def11ad56e0e7bb39a564 (diff) | |
| download | lua-ecf5730c0cc2dde4006a0dded0cf3dd241636cba.tar.gz lua-ecf5730c0cc2dde4006a0dded0cf3dd241636cba.tar.bz2 lua-ecf5730c0cc2dde4006a0dded0cf3dd241636cba.zip | |
(much) smarter way to clear weak tables
| -rw-r--r-- | lgc.c | 94 |
1 files changed, 37 insertions, 57 deletions
| @@ -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 | ||
| 25 | typedef struct GCState { | 25 | typedef 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 | ||
| 140 | static 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 | |||
| 147 | static void traversetable (GCState *st, Table *h) { | 139 | static 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 | ||
| 291 | static 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 | */ | ||
| 287 | static 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 | /* | 298 | static void removekey (Node *n) { |
| 299 | ** clear collected keys from weaktables | 299 | setnilvalue(gval(n)); /* remove corresponding value ... */ |
| 300 | */ | 300 | if (iscollectable(gkey(n))) |
| 301 | static 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 | */ |
| 319 | static void cleartablevalues (GCObject *l) { | 308 | static 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 | ||
| 454 | static void mark (lua_State *L) { | 445 | static 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 | ||
