diff options
| -rw-r--r-- | lgc.c | 120 | ||||
| -rw-r--r-- | lstate.c | 6 | ||||
| -rw-r--r-- | lstate.h | 8 |
3 files changed, 83 insertions, 51 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.c,v 2.40 2006/09/11 14:07:24 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.41 2007/10/29 16:51:20 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 | */ |
| @@ -68,6 +68,24 @@ static void removeentry (Node *n) { | |||
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | 70 | ||
| 71 | /* | ||
| 72 | ** The next function tells whether a key or value can be cleared from | ||
| 73 | ** a weak table. Non-collectable objects are never removed from weak | ||
| 74 | ** tables. Strings behave as `values', so are never removed too. for | ||
| 75 | ** other objects: if really collected, cannot keep them; for userdata | ||
| 76 | ** being finalized, keep them in keys, but not in values | ||
| 77 | */ | ||
| 78 | static int iscleared (const TValue *o, int iskey) { | ||
| 79 | if (!iscollectable(o)) return 0; | ||
| 80 | if (ttisstring(o)) { | ||
| 81 | stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ | ||
| 82 | return 0; | ||
| 83 | } | ||
| 84 | return iswhite(gcvalue(o)) || | ||
| 85 | (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); | ||
| 86 | } | ||
| 87 | |||
| 88 | |||
| 71 | static void reallymarkobject (global_State *g, GCObject *o) { | 89 | static void reallymarkobject (global_State *g, GCObject *o) { |
| 72 | lua_assert(iswhite(o) && !isdead(g, o)); | 90 | lua_assert(iswhite(o) && !isdead(g, o)); |
| 73 | white2gray(o); | 91 | white2gray(o); |
| @@ -157,9 +175,7 @@ size_t luaC_separateudata (lua_State *L, int all) { | |||
| 157 | 175 | ||
| 158 | 176 | ||
| 159 | static void traverseweakvalue (global_State *g, Table *h) { | 177 | static void traverseweakvalue (global_State *g, Table *h) { |
| 160 | int i; | 178 | int i = sizenode(h); |
| 161 | linktable(h, &g->weakvalue); | ||
| 162 | i = sizenode(h); | ||
| 163 | while (i--) { | 179 | while (i--) { |
| 164 | Node *n = gnode(h, i); | 180 | Node *n = gnode(h, i); |
| 165 | lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); | 181 | lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); |
| @@ -170,26 +186,41 @@ static void traverseweakvalue (global_State *g, Table *h) { | |||
| 170 | markvalue(g, gkey(n)); | 186 | markvalue(g, gkey(n)); |
| 171 | } | 187 | } |
| 172 | } | 188 | } |
| 189 | linktable(h, &g->weak); | ||
| 173 | } | 190 | } |
| 174 | 191 | ||
| 175 | 192 | ||
| 176 | static void traverseephemeron (global_State *g, Table *h) { | 193 | static int traverseephemeron (global_State *g, Table *h) { |
| 177 | int i; | 194 | int marked = 0; |
| 178 | linktable(h, &g->weakkey); | 195 | int hasclears = 0; |
| 179 | i = h->sizearray; | 196 | int i = h->sizearray; |
| 180 | while (i--) /* mark array part (numeric keys are 'strong') */ | 197 | while (i--) { /* mark array part (numeric keys are 'strong') */ |
| 181 | markvalue(g, &h->array[i]); | 198 | if (iscollectable(&h->array[i]) && iswhite(gcvalue(&h->array[i]))) { |
| 199 | marked = 1; | ||
| 200 | reallymarkobject(g, gcvalue(&h->array[i])); | ||
| 201 | } | ||
| 202 | } | ||
| 182 | i = sizenode(h); | 203 | i = sizenode(h); |
| 183 | while (i--) { | 204 | while (i--) { |
| 184 | Node *n = gnode(h, i); | 205 | Node *n = gnode(h, i); |
| 185 | lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); | 206 | lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); |
| 186 | if (ttisnil(gval(n))) | 207 | if (ttisnil(gval(n))) /* entry is empty? */ |
| 187 | removeentry(n); /* remove empty entries */ | 208 | removeentry(n); /* remove it */ |
| 188 | else { | 209 | else if (iscollectable(gval(n)) && iswhite(gcvalue(gval(n)))) { |
| 189 | lua_assert(!ttisnil(gkey(n))); | 210 | /* value is not marked yet */ |
| 190 | markvalue(g, gval(n)); | 211 | if (iscleared(key2tval(n), 1)) /* key is not marked (yet)? */ |
| 212 | hasclears = 1; /* may have to propagate mark from key to value */ | ||
| 213 | else { /* mark value only if key is marked */ | ||
| 214 | marked = 1; /* some mark changed status */ | ||
| 215 | reallymarkobject(g, gcvalue(gval(n))); | ||
| 216 | } | ||
| 191 | } | 217 | } |
| 192 | } | 218 | } |
| 219 | if (hasclears) | ||
| 220 | linktable(h, &g->ephemeron); | ||
| 221 | else /* nothing to propagate */ | ||
| 222 | linktable(h, &g->weak); /* avoid convergence phase */ | ||
| 223 | return marked; | ||
| 193 | } | 224 | } |
| 194 | 225 | ||
| 195 | 226 | ||
| @@ -227,7 +258,7 @@ static void traversetable (global_State *g, Table *h) { | |||
| 227 | traverseephemeron(g, h); | 258 | traverseephemeron(g, h); |
| 228 | else { | 259 | else { |
| 229 | lua_assert(weakkey && weakvalue); /* nothing to traverse now */ | 260 | lua_assert(weakkey && weakvalue); /* nothing to traverse now */ |
| 230 | linktable(h, &g->weakkeyvalue); | 261 | linktable(h, &g->allweak); |
| 231 | } | 262 | } |
| 232 | return; | 263 | return; |
| 233 | } /* else go through */ | 264 | } /* else go through */ |
| @@ -307,7 +338,7 @@ static void traversestack (global_State *g, lua_State *l) { | |||
| 307 | for (; o <= lim; o++) | 338 | for (; o <= lim; o++) |
| 308 | setnilvalue(o); | 339 | setnilvalue(o); |
| 309 | if (!g->emergencygc) /* cannot change stack in emergency... */ | 340 | if (!g->emergencygc) /* cannot change stack in emergency... */ |
| 310 | checkstacksizes(l, lim); /* ...(interpreter does not expect that change) */ | 341 | checkstacksizes(l, lim); /* ...(mutator does not expect that change) */ |
| 311 | } | 342 | } |
| 312 | 343 | ||
| 313 | 344 | ||
| @@ -367,24 +398,25 @@ static size_t propagateall (global_State *g) { | |||
| 367 | } | 398 | } |
| 368 | 399 | ||
| 369 | 400 | ||
| 370 | /* | 401 | static void convergeephemerons (global_State *g) { |
| 371 | ** The next function tells whether a key or value can be cleared from | 402 | int changed; |
| 372 | ** a weak table. Non-collectable objects are never removed from weak | 403 | do { |
| 373 | ** tables. Strings behave as `values', so are never removed too. for | 404 | GCObject *w; |
| 374 | ** other objects: if really collected, cannot keep them; for userdata | 405 | GCObject *next = g->ephemeron; |
| 375 | ** being finalized, keep them in keys, but not in values | 406 | g->ephemeron = NULL; |
| 376 | */ | 407 | changed = 0; |
| 377 | static int iscleared (const TValue *o, int iskey) { | 408 | while ((w = next) != NULL) { |
| 378 | if (!iscollectable(o)) return 0; | 409 | next = gco2h(w)->gclist; |
| 379 | if (ttisstring(o)) { | 410 | if (traverseephemeron(g, gco2h(w))) { |
| 380 | stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ | 411 | changed = 1; |
| 381 | return 0; | 412 | propagateall(g); |
| 382 | } | 413 | } |
| 383 | return iswhite(gcvalue(o)) || | 414 | } |
| 384 | (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); | 415 | } while (changed); |
| 385 | } | 416 | } |
| 386 | 417 | ||
| 387 | 418 | ||
| 419 | |||
| 388 | /* | 420 | /* |
| 389 | ** clear collected entries from weaktables | 421 | ** clear collected entries from weaktables |
| 390 | */ | 422 | */ |
| @@ -552,7 +584,7 @@ static void markroot (lua_State *L) { | |||
| 552 | global_State *g = G(L); | 584 | global_State *g = G(L); |
| 553 | g->gray = NULL; | 585 | g->gray = NULL; |
| 554 | g->grayagain = NULL; | 586 | g->grayagain = NULL; |
| 555 | g->weakvalue = g->weakkey = g->weakkeyvalue = NULL; | 587 | g->weak = g->ephemeron = g->allweak = NULL; |
| 556 | markobject(g, g->mainthread); | 588 | markobject(g, g->mainthread); |
| 557 | /* make global table be traversed before main stack */ | 589 | /* make global table be traversed before main stack */ |
| 558 | markvalue(g, gt(g->mainthread)); | 590 | markvalue(g, gt(g->mainthread)); |
| @@ -579,28 +611,30 @@ static void atomic (lua_State *L) { | |||
| 579 | remarkupvals(g); | 611 | remarkupvals(g); |
| 580 | /* traverse objects cautch by write barrier and by 'remarkupvals' */ | 612 | /* traverse objects cautch by write barrier and by 'remarkupvals' */ |
| 581 | propagateall(g); | 613 | propagateall(g); |
| 582 | /* remark value-weak tables */ | 614 | /* remark weak tables */ |
| 583 | g->gray = g->weakvalue; | 615 | g->gray = g->weak; |
| 584 | g->weakvalue = NULL; | 616 | g->weak = NULL; |
| 585 | lua_assert(!iswhite(obj2gco(g->mainthread))); | 617 | lua_assert(!iswhite(obj2gco(g->mainthread))); |
| 586 | markobject(g, L); /* mark running thread */ | 618 | markobject(g, L); /* mark running thread */ |
| 587 | markmt(g); /* mark basic metatables (again) */ | 619 | markmt(g); /* mark basic metatables (again) */ |
| 588 | propagateall(g); | 620 | propagateall(g); |
| 589 | /* remark key-weak tables */ | 621 | /* remark ephemeron tables */ |
| 590 | g->gray = g->weakkey; | 622 | g->gray = g->ephemeron; |
| 591 | g->weakkey = NULL; | 623 | g->ephemeron = NULL; |
| 592 | propagateall(g); | 624 | propagateall(g); |
| 593 | /* remark gray again */ | 625 | /* remark gray again */ |
| 594 | g->gray = g->grayagain; | 626 | g->gray = g->grayagain; |
| 595 | g->grayagain = NULL; | 627 | g->grayagain = NULL; |
| 596 | propagateall(g); | 628 | propagateall(g); |
| 629 | convergeephemerons(g); | ||
| 597 | udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ | 630 | udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ |
| 598 | marktmu(g); /* mark `preserved' userdata */ | 631 | marktmu(g); /* mark `preserved' userdata */ |
| 599 | udsize += propagateall(g); /* remark, to propagate `preserveness' */ | 632 | udsize += propagateall(g); /* remark, to propagate `preserveness' */ |
| 633 | convergeephemerons(g); | ||
| 600 | /* remove collected objects from weak tables */ | 634 | /* remove collected objects from weak tables */ |
| 601 | cleartable(g->weakvalue); | 635 | cleartable(g->weak); |
| 602 | cleartable(g->weakkey); | 636 | cleartable(g->ephemeron); |
| 603 | cleartable(g->weakkeyvalue); | 637 | cleartable(g->allweak); |
| 604 | /* flip current white */ | 638 | /* flip current white */ |
| 605 | g->currentwhite = cast_byte(otherwhite(g)); | 639 | g->currentwhite = cast_byte(otherwhite(g)); |
| 606 | g->sweepstrgc = 0; | 640 | g->sweepstrgc = 0; |
| @@ -699,7 +733,7 @@ void luaC_fullgc (lua_State *L, int isemergency) { | |||
| 699 | /* reset other collector lists */ | 733 | /* reset other collector lists */ |
| 700 | g->gray = NULL; | 734 | g->gray = NULL; |
| 701 | g->grayagain = NULL; | 735 | g->grayagain = NULL; |
| 702 | g->weakvalue = g->weakkey = g->weakkeyvalue = NULL; | 736 | g->weak = g->ephemeron = g->allweak = NULL; |
| 703 | g->gcstate = GCSsweepstring; | 737 | g->gcstate = GCSsweepstring; |
| 704 | } | 738 | } |
| 705 | lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate); | 739 | lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate); |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstate.c,v 2.40 2006/10/10 17:40:17 roberto Exp roberto $ | 2 | ** $Id: lstate.c,v 2.41 2007/10/29 16:51:20 roberto Exp roberto $ |
| 3 | ** Global State | 3 | ** Global State |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -182,9 +182,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
| 182 | g->sweepgc = &g->rootgc; | 182 | g->sweepgc = &g->rootgc; |
| 183 | g->gray = NULL; | 183 | g->gray = NULL; |
| 184 | g->grayagain = NULL; | 184 | g->grayagain = NULL; |
| 185 | g->weakvalue = NULL; | 185 | g->weak = g->ephemeron = g->allweak = NULL; |
| 186 | g->weakkey = NULL; | ||
| 187 | g->weakkeyvalue = NULL; | ||
| 188 | g->tmudata = NULL; | 186 | g->tmudata = NULL; |
| 189 | g->totalbytes = sizeof(LG); | 187 | g->totalbytes = sizeof(LG); |
| 190 | g->gcpause = LUAI_GCPAUSE; | 188 | g->gcpause = LUAI_GCPAUSE; |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstate.h,v 2.28 2007/02/07 17:48:52 roberto Exp roberto $ | 2 | ** $Id: lstate.h,v 2.29 2007/10/29 16:51:20 roberto Exp roberto $ |
| 3 | ** Global State | 3 | ** Global State |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -78,9 +78,9 @@ typedef struct global_State { | |||
| 78 | GCObject **sweepgc; /* position of sweep in `rootgc' */ | 78 | GCObject **sweepgc; /* position of sweep in `rootgc' */ |
| 79 | GCObject *gray; /* list of gray objects */ | 79 | GCObject *gray; /* list of gray objects */ |
| 80 | GCObject *grayagain; /* list of objects to be traversed atomically */ | 80 | GCObject *grayagain; /* list of objects to be traversed atomically */ |
| 81 | GCObject *weakvalue; /* list of value-weak tables */ | 81 | GCObject *weak; /* list of (something) weak tables */ |
| 82 | GCObject *weakkey; /* list of key-weak tables */ | 82 | GCObject *ephemeron; /* list of ephemeron tables */ |
| 83 | GCObject *weakkeyvalue; /* list of all-weak tables */ | 83 | GCObject *allweak; /* list of all-weak tables */ |
| 84 | GCObject *tmudata; /* last element of list of userdata to be GC */ | 84 | GCObject *tmudata; /* last element of list of userdata to be GC */ |
| 85 | Mbuffer buff; /* temporary buffer for string concatentation */ | 85 | Mbuffer buff; /* temporary buffer for string concatentation */ |
| 86 | lu_mem GCthreshold; | 86 | lu_mem GCthreshold; |
