diff options
| -rw-r--r-- | lgc.c | 135 | ||||
| -rw-r--r-- | lgc.h | 6 | ||||
| -rw-r--r-- | lstate.c | 6 | ||||
| -rw-r--r-- | lstate.h | 6 |
4 files changed, 98 insertions, 55 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); |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.h,v 2.15 2005/08/24 16:15:49 roberto Exp roberto $ | 2 | ** $Id: lgc.h,v 2.16 2006/07/11 15:53:29 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,8 +44,6 @@ | |||
| 44 | ** bit 1 - object is white (type 1) | 44 | ** bit 1 - object is white (type 1) |
| 45 | ** bit 2 - object is black | 45 | ** bit 2 - object is black |
| 46 | ** bit 3 - for userdata: has been finalized | 46 | ** bit 3 - for userdata: has been finalized |
| 47 | ** bit 3 - for tables: has weak keys | ||
| 48 | ** bit 4 - for tables: has weak values | ||
| 49 | ** bit 5 - object is fixed (should not be collected) | 47 | ** bit 5 - object is fixed (should not be collected) |
| 50 | ** bit 6 - object is "super" fixed (only the main thread) | 48 | ** bit 6 - object is "super" fixed (only the main thread) |
| 51 | */ | 49 | */ |
| @@ -55,8 +53,6 @@ | |||
| 55 | #define WHITE1BIT 1 | 53 | #define WHITE1BIT 1 |
| 56 | #define BLACKBIT 2 | 54 | #define BLACKBIT 2 |
| 57 | #define FINALIZEDBIT 3 | 55 | #define FINALIZEDBIT 3 |
| 58 | #define KEYWEAKBIT 3 | ||
| 59 | #define VALUEWEAKBIT 4 | ||
| 60 | #define FIXEDBIT 5 | 56 | #define FIXEDBIT 5 |
| 61 | #define SFIXEDBIT 6 | 57 | #define SFIXEDBIT 6 |
| 62 | #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) | 58 | #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstate.c,v 2.39 2006/09/11 14:07:24 roberto Exp roberto $ | 2 | ** $Id: lstate.c,v 2.40 2006/10/10 17:40:17 roberto Exp roberto $ |
| 3 | ** Global State | 3 | ** Global State |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -182,7 +182,9 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
| 182 | g->sweepgc = &g->rootgc; | 182 | g->sweepgc = &g->rootgc; |
| 183 | g->gray = NULL; | 183 | g->gray = NULL; |
| 184 | g->grayagain = NULL; | 184 | g->grayagain = NULL; |
| 185 | g->weak = NULL; | 185 | g->weakvalue = NULL; |
| 186 | g->weakkey = NULL; | ||
| 187 | g->weakkeyvalue = NULL; | ||
| 186 | g->tmudata = NULL; | 188 | g->tmudata = NULL; |
| 187 | g->totalbytes = sizeof(LG); | 189 | g->totalbytes = sizeof(LG); |
| 188 | g->gcpause = LUAI_GCPAUSE; | 190 | g->gcpause = LUAI_GCPAUSE; |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstate.h,v 2.27 2006/09/19 13:57:50 roberto Exp roberto $ | 2 | ** $Id: lstate.h,v 2.28 2007/02/07 17:48:52 roberto Exp roberto $ |
| 3 | ** Global State | 3 | ** Global State |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -78,7 +78,9 @@ typedef struct global_State { | |||
| 78 | GCObject **sweepgc; /* position of sweep in `rootgc' */ | 78 | GCObject **sweepgc; /* position of sweep in `rootgc' */ |
| 79 | GCObject *gray; /* list of gray objects */ | 79 | GCObject *gray; /* list of gray objects */ |
| 80 | GCObject *grayagain; /* list of objects to be traversed atomically */ | 80 | GCObject *grayagain; /* list of objects to be traversed atomically */ |
| 81 | GCObject *weak; /* list of weak tables (to be cleared) */ | 81 | GCObject *weakvalue; /* list of value-weak tables */ |
| 82 | GCObject *weakkey; /* list of key-weak tables */ | ||
| 83 | GCObject *weakkeyvalue; /* list of all-weak tables */ | ||
| 82 | GCObject *tmudata; /* last element of list of userdata to be GC */ | 84 | GCObject *tmudata; /* last element of list of userdata to be GC */ |
| 83 | Mbuffer buff; /* temporary buffer for string concatentation */ | 85 | Mbuffer buff; /* temporary buffer for string concatentation */ |
| 84 | lu_mem GCthreshold; | 86 | lu_mem GCthreshold; |
