diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2011-09-24 18:00:40 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2011-09-24 18:00:40 -0300 |
commit | 95ed6c1127e3d2902ea460947c69a1c14096508a (patch) | |
tree | 36a0672a38ece126177ad061e8e734820757f7d3 | |
parent | 12ab78aca654a45a9409d732b335dd541d8bb488 (diff) | |
download | lua-95ed6c1127e3d2902ea460947c69a1c14096508a.tar.gz lua-95ed6c1127e3d2902ea460947c69a1c14096508a.tar.bz2 lua-95ed6c1127e3d2902ea460947c69a1c14096508a.zip |
better(?) scheme for cleaning weak tables; all ressurected objects
are removed from weak values before finalization
-rw-r--r-- | lgc.c | 62 |
1 files changed, 44 insertions, 18 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.109 2011/05/05 19:42:25 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.110 2011/09/19 17:03:38 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 | */ |
@@ -116,13 +116,13 @@ static void removeentry (Node *n) { | |||
116 | ** other objects: if really collected, cannot keep them; for objects | 116 | ** other objects: if really collected, cannot keep them; for objects |
117 | ** being finalized, keep them in keys, but not in values | 117 | ** being finalized, keep them in keys, but not in values |
118 | */ | 118 | */ |
119 | static int iscleared (const TValue *o, int iskey) { | 119 | static int iscleared (const TValue *o) { |
120 | if (!iscollectable(o)) return 0; | 120 | if (!iscollectable(o)) return 0; |
121 | else if (ttisstring(o)) { | 121 | else if (ttisstring(o)) { |
122 | stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ | 122 | stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ |
123 | return 0; | 123 | return 0; |
124 | } | 124 | } |
125 | else return iswhite(gcvalue(o)) || (!iskey && isfinalized(gcvalue(o))); | 125 | else return iswhite(gcvalue(o)); |
126 | } | 126 | } |
127 | 127 | ||
128 | 128 | ||
@@ -373,14 +373,14 @@ static int traverseephemeron (global_State *g, Table *h) { | |||
373 | checkdeadkey(n); | 373 | checkdeadkey(n); |
374 | if (ttisnil(gval(n))) /* entry is empty? */ | 374 | if (ttisnil(gval(n))) /* entry is empty? */ |
375 | removeentry(n); /* remove it */ | 375 | removeentry(n); /* remove it */ |
376 | else if (iscleared(gkey(n), 1)) { /* key is not marked (yet)? */ | 376 | else if (iscleared(gkey(n))) { /* key is not marked (yet)? */ |
377 | hasclears = 1; /* table still have white keys */ | 377 | hasclears = 1; /* table must be cleared */ |
378 | if (valiswhite(gval(n))) /* value not marked yet? */ | 378 | if (valiswhite(gval(n))) /* value not marked yet? */ |
379 | prop = 1; | 379 | prop = 1; /* must propagate again */ |
380 | } | 380 | } |
381 | else if (valiswhite(gval(n))) { /* value not marked yet? */ | 381 | else if (valiswhite(gval(n))) { /* value not marked yet? */ |
382 | marked = 1; /* mark it now */ | 382 | marked = 1; |
383 | reallymarkobject(g, gcvalue(gval(n))); | 383 | reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ |
384 | } | 384 | } |
385 | } | 385 | } |
386 | if (prop) | 386 | if (prop) |
@@ -566,21 +566,39 @@ static void convergeephemerons (global_State *g) { | |||
566 | 566 | ||
567 | 567 | ||
568 | /* | 568 | /* |
569 | ** clear collected entries from all weaktables in list 'l' | 569 | ** clear entries with unmarked keys from all weaktables in list 'l' up |
570 | ** to element 'f' | ||
571 | */ | ||
572 | static void clearkeys (GCObject *l, GCObject *f) { | ||
573 | for (; l != f; l = gco2t(l)->gclist) { | ||
574 | Table *h = gco2t(l); | ||
575 | Node *n, *limit = gnode(h, sizenode(h)); | ||
576 | for (n = gnode(h, 0); n < limit; n++) { | ||
577 | if (!ttisnil(gval(n)) && (iscleared(gkey(n)))) { | ||
578 | setnilvalue(gval(n)); /* remove value ... */ | ||
579 | removeentry(n); /* and remove entry from table */ | ||
580 | } | ||
581 | } | ||
582 | } | ||
583 | } | ||
584 | |||
585 | |||
586 | /* | ||
587 | ** clear entries with unmarked values from all weaktables in list 'l' up | ||
588 | ** to element 'f' | ||
570 | */ | 589 | */ |
571 | static void cleartable (GCObject *l) { | 590 | static void clearvalues (GCObject *l, GCObject *f) { |
572 | for (; l != NULL; l = gco2t(l)->gclist) { | 591 | for (; l != f; l = gco2t(l)->gclist) { |
573 | Table *h = gco2t(l); | 592 | Table *h = gco2t(l); |
574 | Node *n, *limit = gnode(h, sizenode(h)); | 593 | Node *n, *limit = gnode(h, sizenode(h)); |
575 | int i; | 594 | int i; |
576 | for (i = 0; i < h->sizearray; i++) { | 595 | for (i = 0; i < h->sizearray; i++) { |
577 | TValue *o = &h->array[i]; | 596 | TValue *o = &h->array[i]; |
578 | if (iscleared(o, 0)) /* value was collected? */ | 597 | if (iscleared(o)) /* value was collected? */ |
579 | setnilvalue(o); /* remove value */ | 598 | setnilvalue(o); /* remove value */ |
580 | } | 599 | } |
581 | for (n = gnode(h, 0); n < limit; n++) { | 600 | for (n = gnode(h, 0); n < limit; n++) { |
582 | if (!ttisnil(gval(n)) && /* non-empty entry? */ | 601 | if (!ttisnil(gval(n)) && iscleared(gval(n))) { |
583 | (iscleared(gkey(n), 1) || iscleared(gval(n), 0))) { | ||
584 | setnilvalue(gval(n)); /* remove value ... */ | 602 | setnilvalue(gval(n)); /* remove value ... */ |
585 | removeentry(n); /* and remove entry from table */ | 603 | removeentry(n); /* and remove entry from table */ |
586 | } | 604 | } |
@@ -862,6 +880,7 @@ void luaC_freeallobjects (lua_State *L) { | |||
862 | 880 | ||
863 | static void atomic (lua_State *L) { | 881 | static void atomic (lua_State *L) { |
864 | global_State *g = G(L); | 882 | global_State *g = G(L); |
883 | GCObject *origweak, *origall; | ||
865 | lua_assert(!iswhite(obj2gco(g->mainthread))); | 884 | lua_assert(!iswhite(obj2gco(g->mainthread))); |
866 | markobject(g, L); /* mark running thread */ | 885 | markobject(g, L); /* mark running thread */ |
867 | /* registry and global metatables may be changed by API */ | 886 | /* registry and global metatables may be changed by API */ |
@@ -876,14 +895,21 @@ static void atomic (lua_State *L) { | |||
876 | traverselistofgrays(g, &g->ephemeron); /* remark ephemeron tables */ | 895 | traverselistofgrays(g, &g->ephemeron); /* remark ephemeron tables */ |
877 | convergeephemerons(g); | 896 | convergeephemerons(g); |
878 | /* at this point, all strongly accessible objects are marked. */ | 897 | /* at this point, all strongly accessible objects are marked. */ |
879 | luaC_separateudata(L, 0); /* separate userdata to be finalized */ | 898 | /* clear values from weak tables, before checking finalizers */ |
899 | clearvalues(g->weak, NULL); | ||
900 | clearvalues(g->allweak, NULL); | ||
901 | origweak = g->weak; origall = g->allweak; | ||
902 | luaC_separateudata(L, 0); /* separate objects to be finalized */ | ||
880 | markbeingfnz(g); /* mark userdata that will be finalized */ | 903 | markbeingfnz(g); /* mark userdata that will be finalized */ |
881 | propagateall(g); /* remark, to propagate `preserveness' */ | 904 | propagateall(g); /* remark, to propagate `preserveness' */ |
882 | convergeephemerons(g); | 905 | convergeephemerons(g); |
906 | /* at this point, all accessible objects are marked. */ | ||
883 | /* remove collected objects from weak tables */ | 907 | /* remove collected objects from weak tables */ |
884 | cleartable(g->weak); | 908 | clearkeys(g->ephemeron, NULL); /* clear keys from all ephemeron tables */ |
885 | cleartable(g->ephemeron); | 909 | clearkeys(g->allweak, NULL); /* clear keys from all allweak tables */ |
886 | cleartable(g->allweak); | 910 | /* clear values from weak tables accessible from separated objects */ |
911 | clearvalues(g->weak, origweak); | ||
912 | clearvalues(g->allweak, origall); | ||
887 | g->sweepstrgc = 0; /* prepare to sweep strings */ | 913 | g->sweepstrgc = 0; /* prepare to sweep strings */ |
888 | g->gcstate = GCSsweepstring; | 914 | g->gcstate = GCSsweepstring; |
889 | g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ | 915 | g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ |