diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2007-10-31 13:41:19 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2007-10-31 13:41:19 -0200 |
commit | 5e8dd555748f0f5ef8c7afb5bcc9aa42decc8c81 (patch) | |
tree | 8b9b35b380fa3f6bcf606110903911fb4478b46d /lgc.c | |
parent | 0e961ad47acbe2d67b72c90cc1ba0040f3907b75 (diff) | |
download | lua-5e8dd555748f0f5ef8c7afb5bcc9aa42decc8c81.tar.gz lua-5e8dd555748f0f5ef8c7afb5bcc9aa42decc8c81.tar.bz2 lua-5e8dd555748f0f5ef8c7afb5bcc9aa42decc8c81.zip |
first implementation of ephemerons
Diffstat (limited to 'lgc.c')
-rw-r--r-- | lgc.c | 120 |
1 files changed, 77 insertions, 43 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); |