diff options
Diffstat (limited to 'lgc.c')
-rw-r--r-- | lgc.c | 135 |
1 files changed, 89 insertions, 46 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.39 2006/07/11 15:53:29 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.40 2006/09/11 14:07:24 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 | */ |
@@ -44,10 +44,6 @@ | |||
44 | #define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT) | 44 | #define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT) |
45 | 45 | ||
46 | 46 | ||
47 | #define KEYWEAK bitmask(KEYWEAKBIT) | ||
48 | #define VALUEWEAK bitmask(VALUEWEAKBIT) | ||
49 | |||
50 | |||
51 | 47 | ||
52 | #define markvalue(g,o) { checkconsistency(o); \ | 48 | #define markvalue(g,o) { checkconsistency(o); \ |
53 | if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } | 49 | if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } |
@@ -59,6 +55,12 @@ | |||
59 | #define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause) | 55 | #define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause) |
60 | 56 | ||
61 | 57 | ||
58 | static void linktable (Table *h, GCObject **p) { | ||
59 | h->gclist = *p; | ||
60 | *p = obj2gco(h); | ||
61 | } | ||
62 | |||
63 | |||
62 | static void removeentry (Node *n) { | 64 | static void removeentry (Node *n) { |
63 | lua_assert(ttisnil(gval(n))); | 65 | lua_assert(ttisnil(gval(n))); |
64 | if (iscollectable(gkey(n))) | 66 | if (iscollectable(gkey(n))) |
@@ -93,8 +95,7 @@ static void reallymarkobject (global_State *g, GCObject *o) { | |||
93 | break; | 95 | break; |
94 | } | 96 | } |
95 | case LUA_TTABLE: { | 97 | case LUA_TTABLE: { |
96 | gco2h(o)->gclist = g->gray; | 98 | linktable(gco2h(o), &g->gray); |
97 | g->gray = o; | ||
98 | break; | 99 | break; |
99 | } | 100 | } |
100 | case LUA_TTHREAD: { | 101 | case LUA_TTHREAD: { |
@@ -155,30 +156,48 @@ size_t luaC_separateudata (lua_State *L, int all) { | |||
155 | } | 156 | } |
156 | 157 | ||
157 | 158 | ||
158 | static int traversetable (global_State *g, Table *h) { | 159 | static void traverseweakvalue (global_State *g, Table *h) { |
159 | int i; | 160 | int i; |
160 | int weakkey = 0; | 161 | linktable(h, &g->weakvalue); |
161 | int weakvalue = 0; | 162 | i = sizenode(h); |
162 | const TValue *mode; | 163 | while (i--) { |
163 | markobject(g, h->metatable); | 164 | Node *n = gnode(h, i); |
164 | mode = gfasttm(g, h->metatable, TM_MODE); | 165 | lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); |
165 | if (mode && ttisstring(mode)) { /* is there a weak mode? */ | 166 | if (ttisnil(gval(n))) |
166 | weakkey = (strchr(svalue(mode), 'k') != NULL); | 167 | removeentry(n); /* remove empty entries */ |
167 | weakvalue = (strchr(svalue(mode), 'v') != NULL); | 168 | else { |
168 | if (weakkey || weakvalue) { /* is really weak? */ | 169 | lua_assert(!ttisnil(gkey(n))); |
169 | h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ | 170 | markvalue(g, gkey(n)); |
170 | h->marked |= cast_byte((weakkey << KEYWEAKBIT) | | ||
171 | (weakvalue << VALUEWEAKBIT)); | ||
172 | h->gclist = g->weak; /* must be cleared after GC, ... */ | ||
173 | g->weak = obj2gco(h); /* ... so put in the appropriate list */ | ||
174 | } | 171 | } |
175 | } | 172 | } |
176 | if (weakkey && weakvalue) return 1; | 173 | } |
177 | if (!weakvalue) { | 174 | |
178 | i = h->sizearray; | 175 | |
179 | while (i--) | 176 | static void traverseephemeron (global_State *g, Table *h) { |
180 | markvalue(g, &h->array[i]); | 177 | int i; |
178 | linktable(h, &g->weakkey); | ||
179 | i = h->sizearray; | ||
180 | while (i--) /* mark array part (numeric keys are 'strong') */ | ||
181 | markvalue(g, &h->array[i]); | ||
182 | i = sizenode(h); | ||
183 | while (i--) { | ||
184 | Node *n = gnode(h, i); | ||
185 | lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); | ||
186 | if (ttisnil(gval(n))) | ||
187 | removeentry(n); /* remove empty entries */ | ||
188 | else { | ||
189 | lua_assert(!ttisnil(gkey(n))); | ||
190 | markvalue(g, gval(n)); | ||
191 | } | ||
181 | } | 192 | } |
193 | } | ||
194 | |||
195 | |||
196 | static void traversestrongtable (global_State *g, Table *h) { | ||
197 | int i; | ||
198 | i = h->sizearray; | ||
199 | while (i--) | ||
200 | markvalue(g, &h->array[i]); | ||
182 | i = sizenode(h); | 201 | i = sizenode(h); |
183 | while (i--) { | 202 | while (i--) { |
184 | Node *n = gnode(h, i); | 203 | Node *n = gnode(h, i); |
@@ -187,11 +206,33 @@ static int traversetable (global_State *g, Table *h) { | |||
187 | removeentry(n); /* remove empty entries */ | 206 | removeentry(n); /* remove empty entries */ |
188 | else { | 207 | else { |
189 | lua_assert(!ttisnil(gkey(n))); | 208 | lua_assert(!ttisnil(gkey(n))); |
190 | if (!weakkey) markvalue(g, gkey(n)); | 209 | markvalue(g, gkey(n)); |
191 | if (!weakvalue) markvalue(g, gval(n)); | 210 | markvalue(g, gval(n)); |
192 | } | 211 | } |
193 | } | 212 | } |
194 | return weakkey || weakvalue; | 213 | } |
214 | |||
215 | |||
216 | static void traversetable (global_State *g, Table *h) { | ||
217 | const TValue *mode = gfasttm(g, h->metatable, TM_MODE); | ||
218 | markobject(g, h->metatable); | ||
219 | if (mode && ttisstring(mode)) { /* is there a weak mode? */ | ||
220 | int weakkey = (strchr(svalue(mode), 'k') != NULL); | ||
221 | int weakvalue = (strchr(svalue(mode), 'v') != NULL); | ||
222 | if (weakkey || weakvalue) { /* is really weak? */ | ||
223 | black2gray(obj2gco(h)); /* keep table gray */ | ||
224 | if (!weakkey) /* strong keys? */ | ||
225 | traverseweakvalue(g, h); | ||
226 | else if (!weakvalue) /* strong values? */ | ||
227 | traverseephemeron(g, h); | ||
228 | else { | ||
229 | lua_assert(weakkey && weakvalue); /* nothing to traverse now */ | ||
230 | linktable(h, &g->weakkeyvalue); | ||
231 | } | ||
232 | return; | ||
233 | } /* else go through */ | ||
234 | } | ||
235 | traversestrongtable(g, h); | ||
195 | } | 236 | } |
196 | 237 | ||
197 | 238 | ||
@@ -282,8 +323,7 @@ static l_mem propagatemark (global_State *g) { | |||
282 | case LUA_TTABLE: { | 323 | case LUA_TTABLE: { |
283 | Table *h = gco2h(o); | 324 | Table *h = gco2h(o); |
284 | g->gray = h->gclist; | 325 | g->gray = h->gclist; |
285 | if (traversetable(g, h)) /* table is weak? */ | 326 | traversetable(g, h); |
286 | black2gray(o); /* keep it gray */ | ||
287 | return sizeof(Table) + sizeof(TValue) * h->sizearray + | 327 | return sizeof(Table) + sizeof(TValue) * h->sizearray + |
288 | sizeof(Node) * sizenode(h); | 328 | sizeof(Node) * sizenode(h); |
289 | } | 329 | } |
@@ -352,14 +392,10 @@ static void cleartable (GCObject *l) { | |||
352 | while (l) { | 392 | while (l) { |
353 | Table *h = gco2h(l); | 393 | Table *h = gco2h(l); |
354 | int i = h->sizearray; | 394 | int i = h->sizearray; |
355 | lua_assert(testbit(h->marked, VALUEWEAKBIT) || | 395 | while (i--) { |
356 | testbit(h->marked, KEYWEAKBIT)); | 396 | TValue *o = &h->array[i]; |
357 | if (testbit(h->marked, VALUEWEAKBIT)) { | 397 | if (iscleared(o, 0)) /* value was collected? */ |
358 | while (i--) { | 398 | setnilvalue(o); /* remove value */ |
359 | TValue *o = &h->array[i]; | ||
360 | if (iscleared(o, 0)) /* value was collected? */ | ||
361 | setnilvalue(o); /* remove value */ | ||
362 | } | ||
363 | } | 399 | } |
364 | i = sizenode(h); | 400 | i = sizenode(h); |
365 | while (i--) { | 401 | while (i--) { |
@@ -516,7 +552,7 @@ static void markroot (lua_State *L) { | |||
516 | global_State *g = G(L); | 552 | global_State *g = G(L); |
517 | g->gray = NULL; | 553 | g->gray = NULL; |
518 | g->grayagain = NULL; | 554 | g->grayagain = NULL; |
519 | g->weak = NULL; | 555 | g->weakvalue = g->weakkey = g->weakkeyvalue = NULL; |
520 | markobject(g, g->mainthread); | 556 | markobject(g, g->mainthread); |
521 | /* make global table be traversed before main stack */ | 557 | /* make global table be traversed before main stack */ |
522 | markvalue(g, gt(g->mainthread)); | 558 | markvalue(g, gt(g->mainthread)); |
@@ -543,13 +579,17 @@ static void atomic (lua_State *L) { | |||
543 | remarkupvals(g); | 579 | remarkupvals(g); |
544 | /* traverse objects cautch by write barrier and by 'remarkupvals' */ | 580 | /* traverse objects cautch by write barrier and by 'remarkupvals' */ |
545 | propagateall(g); | 581 | propagateall(g); |
546 | /* remark weak tables */ | 582 | /* remark value-weak tables */ |
547 | g->gray = g->weak; | 583 | g->gray = g->weakvalue; |
548 | g->weak = NULL; | 584 | g->weakvalue = NULL; |
549 | lua_assert(!iswhite(obj2gco(g->mainthread))); | 585 | lua_assert(!iswhite(obj2gco(g->mainthread))); |
550 | markobject(g, L); /* mark running thread */ | 586 | markobject(g, L); /* mark running thread */ |
551 | markmt(g); /* mark basic metatables (again) */ | 587 | markmt(g); /* mark basic metatables (again) */ |
552 | propagateall(g); | 588 | propagateall(g); |
589 | /* remark key-weak tables */ | ||
590 | g->gray = g->weakkey; | ||
591 | g->weakkey = NULL; | ||
592 | propagateall(g); | ||
553 | /* remark gray again */ | 593 | /* remark gray again */ |
554 | g->gray = g->grayagain; | 594 | g->gray = g->grayagain; |
555 | g->grayagain = NULL; | 595 | g->grayagain = NULL; |
@@ -557,7 +597,10 @@ static void atomic (lua_State *L) { | |||
557 | udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ | 597 | udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ |
558 | marktmu(g); /* mark `preserved' userdata */ | 598 | marktmu(g); /* mark `preserved' userdata */ |
559 | udsize += propagateall(g); /* remark, to propagate `preserveness' */ | 599 | udsize += propagateall(g); /* remark, to propagate `preserveness' */ |
560 | cleartable(g->weak); /* remove collected objects from weak tables */ | 600 | /* remove collected objects from weak tables */ |
601 | cleartable(g->weakvalue); | ||
602 | cleartable(g->weakkey); | ||
603 | cleartable(g->weakkeyvalue); | ||
561 | /* flip current white */ | 604 | /* flip current white */ |
562 | g->currentwhite = cast_byte(otherwhite(g)); | 605 | g->currentwhite = cast_byte(otherwhite(g)); |
563 | g->sweepstrgc = 0; | 606 | g->sweepstrgc = 0; |
@@ -656,7 +699,7 @@ void luaC_fullgc (lua_State *L, int isemergency) { | |||
656 | /* reset other collector lists */ | 699 | /* reset other collector lists */ |
657 | g->gray = NULL; | 700 | g->gray = NULL; |
658 | g->grayagain = NULL; | 701 | g->grayagain = NULL; |
659 | g->weak = NULL; | 702 | g->weakvalue = g->weakkey = g->weakkeyvalue = NULL; |
660 | g->gcstate = GCSsweepstring; | 703 | g->gcstate = GCSsweepstring; |
661 | } | 704 | } |
662 | lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate); | 705 | lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate); |