summaryrefslogtreecommitdiff
path: root/lgc.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2007-10-31 13:41:19 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2007-10-31 13:41:19 -0200
commit5e8dd555748f0f5ef8c7afb5bcc9aa42decc8c81 (patch)
tree8b9b35b380fa3f6bcf606110903911fb4478b46d /lgc.c
parent0e961ad47acbe2d67b72c90cc1ba0040f3907b75 (diff)
downloadlua-5e8dd555748f0f5ef8c7afb5bcc9aa42decc8c81.tar.gz
lua-5e8dd555748f0f5ef8c7afb5bcc9aa42decc8c81.tar.bz2
lua-5e8dd555748f0f5ef8c7afb5bcc9aa42decc8c81.zip
first implementation of ephemerons
Diffstat (limited to 'lgc.c')
-rw-r--r--lgc.c120
1 files changed, 77 insertions, 43 deletions
diff --git a/lgc.c b/lgc.c
index 3dc486d3..d9a23307 100644
--- a/lgc.c
+++ b/lgc.c
@@ -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*/
78static 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
71static void reallymarkobject (global_State *g, GCObject *o) { 89static 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
159static void traverseweakvalue (global_State *g, Table *h) { 177static 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
176static void traverseephemeron (global_State *g, Table *h) { 193static 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/* 401static 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;
377static 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);