diff options
| -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 */ |
