diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2004-03-15 18:04:33 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2004-03-15 18:04:33 -0300 |
| commit | a4e1230f95223f2106cf0e118426ba91f1017d89 (patch) | |
| tree | bc6b67ae14a3381498a203e715d48e8d059b6fef | |
| parent | 9804467eeb9836bc147adffee411b21e6257da6b (diff) | |
| download | lua-a4e1230f95223f2106cf0e118426ba91f1017d89.tar.gz lua-a4e1230f95223f2106cf0e118426ba91f1017d89.tar.bz2 lua-a4e1230f95223f2106cf0e118426ba91f1017d89.zip | |
better way to control open upvalues
| -rw-r--r-- | lfunc.c | 22 | ||||
| -rw-r--r-- | lgc.c | 236 | ||||
| -rw-r--r-- | lgc.h | 5 | ||||
| -rw-r--r-- | lobject.h | 3 | ||||
| -rw-r--r-- | lstate.c | 27 |
5 files changed, 159 insertions, 134 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lfunc.c,v 2.1 2003/12/10 12:13:36 roberto Exp roberto $ | 2 | ** $Id: lfunc.c,v 2.2 2004/02/16 19:09:52 roberto Exp roberto $ |
| 3 | ** Auxiliary functions to manipulate prototypes and closures | 3 | ** Auxiliary functions to manipulate prototypes and closures |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -34,6 +34,7 @@ Closure *luaF_newLclosure (lua_State *L, int nelems, TValue *e) { | |||
| 34 | c->l.isC = 0; | 34 | c->l.isC = 0; |
| 35 | c->l.g = *e; | 35 | c->l.g = *e; |
| 36 | c->l.nupvalues = cast(lu_byte, nelems); | 36 | c->l.nupvalues = cast(lu_byte, nelems); |
| 37 | while (nelems--) c->l.upvals[nelems] = NULL; | ||
| 37 | return c; | 38 | return c; |
| 38 | } | 39 | } |
| 39 | 40 | ||
| @@ -67,17 +68,18 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { | |||
| 67 | 68 | ||
| 68 | void luaF_close (lua_State *L, StkId level) { | 69 | void luaF_close (lua_State *L, StkId level) { |
| 69 | UpVal *uv; | 70 | UpVal *uv; |
| 71 | global_State *g = G(L); | ||
| 70 | while ((uv = ngcotouv(L->openupval)) != NULL && uv->v >= level) { | 72 | while ((uv = ngcotouv(L->openupval)) != NULL && uv->v >= level) { |
| 71 | lu_byte mark = uv->marked; | 73 | GCObject *o = obj2gco(uv); |
| 72 | lua_assert(!isblack(obj2gco(uv))); | 74 | lua_assert(!isblack(o)); |
| 73 | setobj(L, &uv->value, uv->v); | ||
| 74 | luaC_barrier(L, uv, uv->v); | ||
| 75 | uv->v = &uv->value; /* now current value lives here */ | ||
| 76 | L->openupval = uv->next; /* remove from `open' list */ | 75 | L->openupval = uv->next; /* remove from `open' list */ |
| 77 | luaC_link(L, obj2gco(uv), LUA_TUPVAL); | 76 | if (isdead(g, o)) |
| 78 | if (G(L)->gcstate == GCSpropagate) | 77 | luaM_freelem(L, uv); /* free upvalue */ |
| 79 | uv->marked = mark; /* preserve previous mark */ | 78 | else { |
| 80 | lua_assert(!isdead(G(L), obj2gco(uv))); | 79 | setobj(L, &uv->value, uv->v); |
| 80 | uv->v = &uv->value; /* now current value lives here */ | ||
| 81 | luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */ | ||
| 82 | } | ||
| 81 | } | 83 | } |
| 82 | } | 84 | } |
| 83 | 85 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.c,v 2.3 2004/02/16 19:09:52 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.4 2004/03/09 17:34:35 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 | */ |
| @@ -27,15 +27,16 @@ | |||
| 27 | #define GCSWEEPCOST sizeof(TValue) | 27 | #define GCSWEEPCOST sizeof(TValue) |
| 28 | 28 | ||
| 29 | 29 | ||
| 30 | #define gray2black(x) setbit((x)->gch.marked, BLACKBIT) | 30 | #define FIXEDMASK bitmask(FIXEDBIT) |
| 31 | 31 | ||
| 32 | #define maskmarks \ | 32 | #define maskmarks \ |
| 33 | cast(lu_byte, ~(bitmask(BLACKBIT)|bit2mask(WHITE0BIT, WHITE1BIT))) | 33 | cast(lu_byte, ~(bitmask(BLACKBIT)|bit2mask(WHITE0BIT, WHITE1BIT))) |
| 34 | |||
| 34 | #define makewhite(g,x) \ | 35 | #define makewhite(g,x) \ |
| 35 | ((x)->gch.marked = ((x)->gch.marked & maskmarks) | g->currentwhite) | 36 | ((x)->gch.marked = ((x)->gch.marked & maskmarks) | g->currentwhite) |
| 36 | 37 | ||
| 37 | #define isgray(x) (!isblack(x) && !iswhite(x)) | ||
| 38 | #define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) | 38 | #define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) |
| 39 | #define gray2black(x) setbit((x)->gch.marked, BLACKBIT) | ||
| 39 | #define black2gray(x) resetbit((x)->gch.marked, BLACKBIT) | 40 | #define black2gray(x) resetbit((x)->gch.marked, BLACKBIT) |
| 40 | 41 | ||
| 41 | #define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) | 42 | #define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) |
| @@ -58,47 +59,10 @@ | |||
| 58 | 59 | ||
| 59 | 60 | ||
| 60 | 61 | ||
| 61 | 62 | static void removeentry (Node *n) { | |
| 62 | /* | 63 | setnilvalue(gval(n)); /* remove corresponding value ... */ |
| 63 | ** computes the size of a collectible object | 64 | if (iscollectable(gkey(n))) |
| 64 | */ | 65 | setttype(gkey(n), LUA_TNONE); /* dead key; remove it */ |
| 65 | static size_t objsize (GCObject *o) { | ||
| 66 | switch (o->gch.tt) { | ||
| 67 | case LUA_TSTRING: { | ||
| 68 | TString *ts = rawgco2ts(o); | ||
| 69 | return sizestring(ts->tsv.len); | ||
| 70 | } | ||
| 71 | case LUA_TUSERDATA: { | ||
| 72 | Udata *u = rawgco2u(o); | ||
| 73 | return sizeudata(u->uv.len); | ||
| 74 | } | ||
| 75 | case LUA_TTABLE: { | ||
| 76 | Table *h = gco2h(o); | ||
| 77 | return sizeof(Table) + sizeof(TValue) * h->sizearray + | ||
| 78 | sizeof(Node) * sizenode(h); | ||
| 79 | } | ||
| 80 | case LUA_TUPVAL: | ||
| 81 | return sizeof(UpVal); | ||
| 82 | case LUA_TFUNCTION: { | ||
| 83 | Closure *cl = gco2cl(o); | ||
| 84 | return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : | ||
| 85 | sizeLclosure(cl->l.nupvalues); | ||
| 86 | } | ||
| 87 | case LUA_TTHREAD: { | ||
| 88 | lua_State *th = gco2th(o); | ||
| 89 | return sizeof(lua_State) + sizeof(TValue) * th->stacksize + | ||
| 90 | sizeof(CallInfo) * th->size_ci; | ||
| 91 | } | ||
| 92 | case LUA_TPROTO: { | ||
| 93 | Proto *p = gco2p(o); | ||
| 94 | return sizeof(Proto) + sizeof(Instruction) * p->sizecode + | ||
| 95 | sizeof(Proto *) * p->sizep + sizeof(TValue) * p->sizek + | ||
| 96 | sizeof(int) * p->sizelineinfo + sizeof(LocVar) * p->sizelocvars + | ||
| 97 | sizeof(TString *) * p->sizeupvalues; | ||
| 98 | } | ||
| 99 | } | ||
| 100 | lua_assert(0); | ||
| 101 | return 0; /* to avoid warnings */ | ||
| 102 | } | 66 | } |
| 103 | 67 | ||
| 104 | 68 | ||
| @@ -115,29 +79,36 @@ static void reallymarkobject (global_State *g, GCObject *o) { | |||
| 115 | if (mt) markobject(g, mt); | 79 | if (mt) markobject(g, mt); |
| 116 | return; | 80 | return; |
| 117 | } | 81 | } |
| 82 | case LUA_TUPVAL: { | ||
| 83 | UpVal *uv = gco2uv(o); | ||
| 84 | if (uv->v == &uv->value) { /* closed? */ | ||
| 85 | markvalue(g, uv->v); | ||
| 86 | gray2black(o); | ||
| 87 | } | ||
| 88 | return; | ||
| 89 | } | ||
| 118 | case LUA_TFUNCTION: { | 90 | case LUA_TFUNCTION: { |
| 119 | gco2cl(o)->c.gclist = g->gray; | 91 | gco2cl(o)->c.gclist = g->gray; |
| 92 | g->gray = o; | ||
| 120 | break; | 93 | break; |
| 121 | } | 94 | } |
| 122 | case LUA_TTABLE: { | 95 | case LUA_TTABLE: { |
| 123 | gco2h(o)->gclist = g->gray; | 96 | gco2h(o)->gclist = g->gray; |
| 97 | g->gray = o; | ||
| 124 | break; | 98 | break; |
| 125 | } | 99 | } |
| 126 | case LUA_TTHREAD: { | 100 | case LUA_TTHREAD: { |
| 127 | gco2th(o)->gclist = g->gray; | 101 | gco2th(o)->gclist = g->gray; |
| 102 | g->gray = o; | ||
| 128 | break; | 103 | break; |
| 129 | } | 104 | } |
| 130 | case LUA_TPROTO: { | 105 | case LUA_TPROTO: { |
| 131 | gco2p(o)->gclist = g->gray; | 106 | gco2p(o)->gclist = g->gray; |
| 132 | break; | 107 | g->gray = o; |
| 133 | } | ||
| 134 | case LUA_TUPVAL: { | ||
| 135 | gco2uv(o)->gclist = g->gray; | ||
| 136 | break; | 108 | break; |
| 137 | } | 109 | } |
| 138 | default: lua_assert(0); | 110 | default: lua_assert(0); |
| 139 | } | 111 | } |
| 140 | g->gray = o; /* finish list linking */ | ||
| 141 | } | 112 | } |
| 142 | 113 | ||
| 143 | 114 | ||
| @@ -157,8 +128,7 @@ size_t luaC_separateudata (lua_State *L, int all) { | |||
| 157 | GCObject *curr; | 128 | GCObject *curr; |
| 158 | GCObject *collected = NULL; /* to collect udata with gc event */ | 129 | GCObject *collected = NULL; /* to collect udata with gc event */ |
| 159 | GCObject **lastcollected = &collected; | 130 | GCObject **lastcollected = &collected; |
| 160 | while ((curr = *p) != NULL) { | 131 | while ((curr = *p)->gch.tt == LUA_TUSERDATA) { |
| 161 | lua_assert(curr->gch.tt == LUA_TUSERDATA); | ||
| 162 | if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) | 132 | if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) |
| 163 | p = &curr->gch.next; /* don't bother with them */ | 133 | p = &curr->gch.next; /* don't bother with them */ |
| 164 | else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { | 134 | else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { |
| @@ -174,6 +144,7 @@ size_t luaC_separateudata (lua_State *L, int all) { | |||
| 174 | lastcollected = &curr->gch.next; | 144 | lastcollected = &curr->gch.next; |
| 175 | } | 145 | } |
| 176 | } | 146 | } |
| 147 | lua_assert(curr == obj2gco(G(L)->mainthread)); | ||
| 177 | /* insert collected udata with gc event into `tmudata' list */ | 148 | /* insert collected udata with gc event into `tmudata' list */ |
| 178 | *lastcollected = G(L)->tmudata; | 149 | *lastcollected = G(L)->tmudata; |
| 179 | G(L)->tmudata = collected; | 150 | G(L)->tmudata = collected; |
| @@ -210,7 +181,9 @@ static int traversetable (global_State *g, Table *h) { | |||
| 210 | i = sizenode(h); | 181 | i = sizenode(h); |
| 211 | while (i--) { | 182 | while (i--) { |
| 212 | Node *n = gnode(h, i); | 183 | Node *n = gnode(h, i); |
| 213 | if (!ttisnil(gval(n))) { | 184 | if (ttisnil(gval(n))) |
| 185 | removeentry(n); /* remove empty entries */ | ||
| 186 | else { | ||
| 214 | lua_assert(!ttisnil(gkey(n))); | 187 | lua_assert(!ttisnil(gkey(n))); |
| 215 | if (!weakkey) markvalue(g, gkey(n)); | 188 | if (!weakkey) markvalue(g, gkey(n)); |
| 216 | if (!weakvalue) markvalue(g, gval(n)); | 189 | if (!weakvalue) markvalue(g, gval(n)); |
| @@ -274,20 +247,20 @@ static void checkstacksizes (lua_State *L, StkId max) { | |||
| 274 | } | 247 | } |
| 275 | 248 | ||
| 276 | 249 | ||
| 277 | static void traversestack (global_State *g, lua_State *L1) { | 250 | static void traversestack (global_State *g, lua_State *l) { |
| 278 | StkId o, lim; | 251 | StkId o, lim; |
| 279 | CallInfo *ci; | 252 | CallInfo *ci; |
| 280 | markvalue(g, gt(L1)); | 253 | markvalue(g, gt(l)); |
| 281 | lim = L1->top; | 254 | lim = l->top; |
| 282 | for (ci = L1->base_ci; ci <= L1->ci; ci++) { | 255 | for (ci = l->base_ci; ci <= l->ci; ci++) { |
| 283 | lua_assert(ci->top <= L1->stack_last); | 256 | lua_assert(ci->top <= l->stack_last); |
| 284 | if (lim < ci->top) lim = ci->top; | 257 | if (lim < ci->top) lim = ci->top; |
| 285 | } | 258 | } |
| 286 | for (o = L1->stack; o < L1->top; o++) | 259 | for (o = l->stack; o < l->top; o++) |
| 287 | markvalue(g, o); | 260 | markvalue(g, o); |
| 288 | for (; o <= lim; o++) | 261 | for (; o <= lim; o++) |
| 289 | setnilvalue(o); | 262 | setnilvalue(o); |
| 290 | checkstacksizes(L1, lim); | 263 | checkstacksizes(l, lim); |
| 291 | } | 264 | } |
| 292 | 265 | ||
| 293 | 266 | ||
| @@ -306,12 +279,16 @@ static l_mem propagatemarks (global_State *g, l_mem lim) { | |||
| 306 | g->gray = h->gclist; | 279 | g->gray = h->gclist; |
| 307 | if (traversetable(g, h)) /* table is weak? */ | 280 | if (traversetable(g, h)) /* table is weak? */ |
| 308 | black2gray(o); /* keep it gray */ | 281 | black2gray(o); /* keep it gray */ |
| 282 | lim -= sizeof(Table) + sizeof(TValue) * h->sizearray + | ||
| 283 | sizeof(Node) * sizenode(h); | ||
| 309 | break; | 284 | break; |
| 310 | } | 285 | } |
| 311 | case LUA_TFUNCTION: { | 286 | case LUA_TFUNCTION: { |
| 312 | Closure *cl = gco2cl(o); | 287 | Closure *cl = gco2cl(o); |
| 313 | g->gray = cl->c.gclist; | 288 | g->gray = cl->c.gclist; |
| 314 | traverseclosure(g, cl); | 289 | traverseclosure(g, cl); |
| 290 | lim -= (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : | ||
| 291 | sizeLclosure(cl->l.nupvalues); | ||
| 315 | break; | 292 | break; |
| 316 | } | 293 | } |
| 317 | case LUA_TTHREAD: { | 294 | case LUA_TTHREAD: { |
| @@ -321,29 +298,24 @@ static l_mem propagatemarks (global_State *g, l_mem lim) { | |||
| 321 | g->grayagain = o; | 298 | g->grayagain = o; |
| 322 | black2gray(o); | 299 | black2gray(o); |
| 323 | traversestack(g, th); | 300 | traversestack(g, th); |
| 301 | lim -= sizeof(lua_State) + sizeof(TValue) * th->stacksize + | ||
| 302 | sizeof(CallInfo) * th->size_ci; | ||
| 324 | break; | 303 | break; |
| 325 | } | 304 | } |
| 326 | case LUA_TPROTO: { | 305 | case LUA_TPROTO: { |
| 327 | Proto *p = gco2p(o); | 306 | Proto *p = gco2p(o); |
| 328 | g->gray = p->gclist; | 307 | g->gray = p->gclist; |
| 329 | traverseproto(g, p); | 308 | traverseproto(g, p); |
| 330 | break; | 309 | lim -= sizeof(Proto) + sizeof(Instruction) * p->sizecode + |
| 331 | } | 310 | sizeof(Proto *) * p->sizep + |
| 332 | case LUA_TUPVAL: { | 311 | sizeof(TValue) * p->sizek + |
| 333 | UpVal *uv = gco2uv(o); | 312 | sizeof(int) * p->sizelineinfo + |
| 334 | g->gray = uv->gclist; | 313 | sizeof(LocVar) * p->sizelocvars + |
| 335 | if (uv->v != &uv->value) { /* open? */ | 314 | sizeof(TString *) * p->sizeupvalues; |
| 336 | uv->gclist = g->grayagain; | ||
| 337 | g->grayagain = o; | ||
| 338 | black2gray(o); | ||
| 339 | } | ||
| 340 | else | ||
| 341 | markvalue(g, &uv->value); | ||
| 342 | break; | 315 | break; |
| 343 | } | 316 | } |
| 344 | default: lua_assert(0); | 317 | default: lua_assert(0); |
| 345 | } | 318 | } |
| 346 | lim -= objsize(o); | ||
| 347 | if (lim <= 0) return lim; | 319 | if (lim <= 0) return lim; |
| 348 | } | 320 | } |
| 349 | return lim; | 321 | return lim; |
| @@ -368,13 +340,6 @@ static int iscleared (const TValue *o, int iskey) { | |||
| 368 | } | 340 | } |
| 369 | 341 | ||
| 370 | 342 | ||
| 371 | static void removekey (Node *n) { | ||
| 372 | setnilvalue(gval(n)); /* remove corresponding value ... */ | ||
| 373 | if (iscollectable(gkey(n))) | ||
| 374 | setttype(gkey(n), LUA_TNONE); /* dead key; remove it */ | ||
| 375 | } | ||
| 376 | |||
| 377 | |||
| 378 | /* | 343 | /* |
| 379 | ** clear collected entries from weaktables | 344 | ** clear collected entries from weaktables |
| 380 | */ | 345 | */ |
| @@ -396,7 +361,7 @@ static void cleartable (GCObject *l) { | |||
| 396 | Node *n = gnode(h, i); | 361 | Node *n = gnode(h, i); |
| 397 | if (!ttisnil(gval(n)) && /* non-empty entry? */ | 362 | if (!ttisnil(gval(n)) && /* non-empty entry? */ |
| 398 | (iscleared(gkey(n), 1) || iscleared(gval(n), 0))) | 363 | (iscleared(gkey(n), 1) || iscleared(gval(n), 0))) |
| 399 | removekey(n); /* remove entry from table */ | 364 | removeentry(n); /* remove entry from table */ |
| 400 | } | 365 | } |
| 401 | l = h->gclist; | 366 | l = h->gclist; |
| 402 | } | 367 | } |
| @@ -427,22 +392,28 @@ static void freeobj (lua_State *L, GCObject *o) { | |||
| 427 | } | 392 | } |
| 428 | 393 | ||
| 429 | 394 | ||
| 430 | static void sweepupvalues (global_State *g, lua_State *L1) { | 395 | static void sweepupvalues (global_State *g, lua_State *l) { |
| 431 | GCObject *curr; | 396 | GCObject *curr; |
| 432 | for (curr = L1->openupval; curr != NULL; curr = curr->gch.next) | 397 | for (curr = l->openupval; curr != NULL; curr = curr->gch.next) |
| 433 | makewhite(g, curr); | 398 | makewhite(g, curr); |
| 434 | } | 399 | } |
| 435 | 400 | ||
| 436 | 401 | ||
| 437 | static GCObject **sweeplist (lua_State *L, GCObject **p, int all, | 402 | /* |
| 403 | ** macros to test dead bit and optionally the fix bit | ||
| 404 | */ | ||
| 405 | #define makedeadmask(g,kf) (otherwhite(g) | ((kf) ? FIXEDMASK : 0)) | ||
| 406 | #define notdead(mark,mask) ((((mark) ^ FIXEDMASK) & mask) != mask) | ||
| 407 | |||
| 408 | |||
| 409 | static GCObject **sweeplist (lua_State *L, GCObject **p, int keepfixed, | ||
| 438 | l_mem *plim) { | 410 | l_mem *plim) { |
| 439 | GCObject *curr; | 411 | GCObject *curr; |
| 440 | global_State *g = G(L); | 412 | global_State *g = G(L); |
| 441 | l_mem lim = *plim; | 413 | l_mem lim = *plim; |
| 442 | int dead = otherwhite(g); | 414 | int deadmask = makedeadmask(g, keepfixed); |
| 443 | while ((curr = *p) != NULL) { | 415 | while ((curr = *p) != NULL) { |
| 444 | int mark = curr->gch.marked; | 416 | if (notdead(curr->gch.marked, deadmask)) { |
| 445 | if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) { | ||
| 446 | makewhite(g, curr); | 417 | makewhite(g, curr); |
| 447 | if (curr->gch.tt == LUA_TTHREAD) | 418 | if (curr->gch.tt == LUA_TTHREAD) |
| 448 | sweepupvalues(g, gco2th(curr)); | 419 | sweepupvalues(g, gco2th(curr)); |
| @@ -450,6 +421,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int all, | |||
| 450 | lim -= GCSWEEPCOST; | 421 | lim -= GCSWEEPCOST; |
| 451 | } | 422 | } |
| 452 | else { | 423 | else { |
| 424 | lua_assert(iswhite(curr)); | ||
| 453 | *p = curr->gch.next; | 425 | *p = curr->gch.next; |
| 454 | if (curr == g->rootgc) /* is the first element of the list? */ | 426 | if (curr == g->rootgc) /* is the first element of the list? */ |
| 455 | g->rootgc = curr->gch.next; /* adjust first */ | 427 | g->rootgc = curr->gch.next; /* adjust first */ |
| @@ -463,22 +435,22 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int all, | |||
| 463 | } | 435 | } |
| 464 | 436 | ||
| 465 | 437 | ||
| 466 | static l_mem sweepstrings (lua_State *L, int all, l_mem lim) { | 438 | static l_mem sweepstrings (lua_State *L, int keepfixed, l_mem lim) { |
| 467 | int i; | 439 | int i; |
| 468 | global_State *g = G(L); | 440 | global_State *g = G(L); |
| 469 | int dead = otherwhite(g); | 441 | int deadmask = makedeadmask(g, keepfixed); |
| 470 | for (i = g->sweepstrgc; i < g->strt.size; i++) { /* for each list */ | 442 | for (i = g->sweepstrgc; i < g->strt.size; i++) { /* for each list */ |
| 471 | GCObject *curr; | 443 | GCObject *curr; |
| 472 | GCObject **p = &G(L)->strt.hash[i]; | 444 | GCObject **p = &G(L)->strt.hash[i]; |
| 473 | while ((curr = *p) != NULL) { | 445 | while ((curr = *p) != NULL) { |
| 474 | int mark = curr->gch.marked; | ||
| 475 | lu_mem size = sizestring(gco2ts(curr)->len); | 446 | lu_mem size = sizestring(gco2ts(curr)->len); |
| 476 | if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) { | 447 | if (notdead(curr->gch.marked, deadmask)) { |
| 477 | makewhite(g, curr); | 448 | makewhite(g, curr); |
| 478 | lua_assert(iswhite(curr) && !isdead(g, curr)); | 449 | lua_assert(iswhite(curr) && !isdead(g, curr)); |
| 479 | p = &curr->gch.next; | 450 | p = &curr->gch.next; |
| 480 | } | 451 | } |
| 481 | else { | 452 | else { |
| 453 | lua_assert(iswhite(curr)); | ||
| 482 | g->strt.nuse--; | 454 | g->strt.nuse--; |
| 483 | *p = curr->gch.next; | 455 | *p = curr->gch.next; |
| 484 | luaM_free(L, curr, size); | 456 | luaM_free(L, curr, size); |
| @@ -538,10 +510,19 @@ void luaC_callGCTM (lua_State *L) { | |||
| 538 | 510 | ||
| 539 | 511 | ||
| 540 | void luaC_sweepall (lua_State *L) { | 512 | void luaC_sweepall (lua_State *L) { |
| 513 | global_State *g = G(L); | ||
| 541 | l_mem dummy = MAXLMEM; | 514 | l_mem dummy = MAXLMEM; |
| 542 | G(L)->sweepstrgc = 0; | 515 | /* finish (occasional) current sweep */ |
| 543 | sweepstrings(L, 1, dummy); | 516 | markobject(g, g->mainthread); /* cannot collect main thread */ |
| 544 | sweeplist(L, &G(L)->rootgc, 1, &dummy); | 517 | sweepstrings(L, 0, MAXLMEM); |
| 518 | sweeplist(L, &g->rootgc, 0, &dummy); | ||
| 519 | /* do a whole new sweep */ | ||
| 520 | markobject(g, g->mainthread); /* cannot collect main thread */ | ||
| 521 | g->currentwhite = otherwhite(g); | ||
| 522 | g->sweepgc = &g->rootgc; | ||
| 523 | g->sweepstrgc = 0; | ||
| 524 | sweepstrings(L, 0, MAXLMEM); | ||
| 525 | sweeplist(L, &g->rootgc, 0, &dummy); | ||
| 545 | } | 526 | } |
| 546 | 527 | ||
| 547 | 528 | ||
| @@ -559,12 +540,30 @@ static void markroot (lua_State *L) { | |||
| 559 | } | 540 | } |
| 560 | 541 | ||
| 561 | 542 | ||
| 543 | static void remarkupvals (global_State *g) { | ||
| 544 | GCObject *o; | ||
| 545 | for (o = obj2gco(g->mainthread); o; o = o->gch.next) { | ||
| 546 | if (iswhite(o)) { | ||
| 547 | GCObject *curr; | ||
| 548 | for (curr = gco2th(o)->openupval; curr != NULL; curr = curr->gch.next) { | ||
| 549 | if (isgray(curr)) | ||
| 550 | markvalue(g, gco2uv(curr)->v); | ||
| 551 | } | ||
| 552 | } | ||
| 553 | } | ||
| 554 | } | ||
| 555 | |||
| 556 | |||
| 562 | static void atomic (lua_State *L) { | 557 | static void atomic (lua_State *L) { |
| 563 | global_State *g = G(L); | 558 | global_State *g = G(L); |
| 564 | lua_assert(g->gray == NULL); | 559 | lua_assert(g->gray == NULL); |
| 560 | /* remark occasional upvalues of (maybe) dead threads */ | ||
| 561 | remarkupvals(g); | ||
| 565 | /* remark weak tables */ | 562 | /* remark weak tables */ |
| 566 | g->gray = g->weak; | 563 | g->gray = g->weak; |
| 567 | g->weak = NULL; | 564 | g->weak = NULL; |
| 565 | lua_assert(!iswhite(obj2gco(g->mainthread))); | ||
| 566 | markobject(g, L); /* mark running thread */ | ||
| 568 | propagatemarks(g, MAXLMEM); | 567 | propagatemarks(g, MAXLMEM); |
| 569 | /* remark gray again */ | 568 | /* remark gray again */ |
| 570 | g->gray = g->grayagain; | 569 | g->gray = g->grayagain; |
| @@ -576,8 +575,6 @@ static void atomic (lua_State *L) { | |||
| 576 | cleartable(g->weak); /* remove collected objects from weak tables */ | 575 | cleartable(g->weak); /* remove collected objects from weak tables */ |
| 577 | /* flip current white */ | 576 | /* flip current white */ |
| 578 | g->currentwhite = otherwhite(g); | 577 | g->currentwhite = otherwhite(g); |
| 579 | g->sweepgc = &g->rootgc; | ||
| 580 | g->sweepstrgc = 0; | ||
| 581 | g->gcstate = GCSsweepstring; | 578 | g->gcstate = GCSsweepstring; |
| 582 | } | 579 | } |
| 583 | 580 | ||
| @@ -587,38 +584,41 @@ static l_mem singlestep (lua_State *L, l_mem lim) { | |||
| 587 | switch (g->gcstate) { | 584 | switch (g->gcstate) { |
| 588 | case GCSpropagate: { | 585 | case GCSpropagate: { |
| 589 | if (g->gray) | 586 | if (g->gray) |
| 590 | return propagatemarks(g, lim); | 587 | lim = propagatemarks(g, lim); |
| 591 | else { /* no more `gray' objects */ | 588 | else { /* no more `gray' objects */ |
| 592 | atomic(L); /* finish mark phase */ | 589 | atomic(L); /* finish mark phase */ |
| 593 | return 0; | 590 | lim = 0; |
| 594 | } | 591 | } |
| 592 | break; | ||
| 595 | } | 593 | } |
| 596 | case GCSsweepstring: { | 594 | case GCSsweepstring: { |
| 597 | lim = sweepstrings(L, 0, lim); | 595 | lim = sweepstrings(L, 1, lim); |
| 598 | if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */ | 596 | if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */ |
| 599 | g->sweepstrgc = 0; | 597 | g->sweepstrgc = 0; |
| 600 | g->gcstate = GCSsweep; /* end sweep-string phase */ | 598 | g->gcstate = GCSsweep; /* end sweep-string phase */ |
| 601 | } | 599 | } |
| 602 | return lim; | 600 | break; |
| 603 | } | 601 | } |
| 604 | case GCSsweep: { | 602 | case GCSsweep: { |
| 605 | g->sweepgc = sweeplist(L, g->sweepgc, 0, &lim); | 603 | g->sweepgc = sweeplist(L, g->sweepgc, 1, &lim); |
| 606 | if (*g->sweepgc == NULL) { /* nothing more to sweep? */ | 604 | if (*g->sweepgc == NULL) { /* nothing more to sweep? */ |
| 607 | checkSizes(L); | 605 | checkSizes(L); |
| 608 | sweepupvalues(g, g->mainthread); | 606 | g->sweepgc = &g->rootgc; |
| 609 | g->gcstate = GCSfinalize; /* end sweep phase */ | 607 | g->gcstate = GCSfinalize; /* end sweep phase */ |
| 610 | } | 608 | } |
| 611 | return lim; | 609 | break; |
| 612 | } | 610 | } |
| 613 | case GCSfinalize: { | 611 | case GCSfinalize: { |
| 614 | if (g->tmudata) | 612 | if (g->tmudata) |
| 615 | GCTM(L); | 613 | GCTM(L); |
| 616 | else /* no more `udata' to finalize */ | 614 | else /* no more `udata' to finalize */ |
| 617 | markroot(L); /* may restart collection */ | 615 | markroot(L); /* may restart collection */ |
| 618 | return 0; | 616 | lim = 0; |
| 617 | break; | ||
| 619 | } | 618 | } |
| 620 | default: lua_assert(0); return 0; /* to avoid warnings */ | 619 | default: lua_assert(0); |
| 621 | } | 620 | } |
| 621 | return lim; | ||
| 622 | } | 622 | } |
| 623 | 623 | ||
| 624 | 624 | ||
| @@ -635,11 +635,15 @@ void luaC_step (lua_State *L) { | |||
| 635 | 635 | ||
| 636 | void luaC_fullgc (lua_State *L) { | 636 | void luaC_fullgc (lua_State *L) { |
| 637 | global_State *g = G(L); | 637 | global_State *g = G(L); |
| 638 | while (g->gcstate != GCSfinalize) singlestep(L, MAXLMEM); | 638 | while (g->gcstate != GCSfinalize) { |
| 639 | singlestep(L, MAXLMEM); | ||
| 640 | } | ||
| 639 | markroot(L); | 641 | markroot(L); |
| 640 | while (g->gcstate != GCSfinalize) singlestep(L, MAXLMEM); | 642 | while (g->gcstate != GCSfinalize) { |
| 641 | luaC_callGCTM(L); /* call finalizers */ | 643 | singlestep(L, MAXLMEM); |
| 644 | } | ||
| 642 | g->GCthreshold = g->nblocks + GCSTEPSIZE; | 645 | g->GCthreshold = g->nblocks + GCSTEPSIZE; |
| 646 | luaC_callGCTM(L); /* call finalizers */ | ||
| 643 | } | 647 | } |
| 644 | 648 | ||
| 645 | 649 | ||
| @@ -662,3 +666,21 @@ void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { | |||
| 662 | o->gch.tt = tt; | 666 | o->gch.tt = tt; |
| 663 | } | 667 | } |
| 664 | 668 | ||
| 669 | |||
| 670 | void luaC_linkupval (lua_State *L, UpVal *uv) { | ||
| 671 | global_State *g = G(L); | ||
| 672 | GCObject *o = obj2gco(uv); | ||
| 673 | o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ | ||
| 674 | g->rootgc = o; | ||
| 675 | if (isgray(o)) { | ||
| 676 | if (g->gcstate == GCSpropagate) { | ||
| 677 | gray2black(o); /* closed upvalues need barrier */ | ||
| 678 | luaC_barrier(L, uv, uv->v); | ||
| 679 | } | ||
| 680 | else { /* sweep phase: sweep it (turning it into white) */ | ||
| 681 | makewhite(g, o); | ||
| 682 | lua_assert(g->gcstate != GCSfinalize); | ||
| 683 | } | ||
| 684 | } | ||
| 685 | } | ||
| 686 | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.h,v 2.3 2004/02/16 19:09:52 roberto Exp roberto $ | 2 | ** $Id: lgc.h,v 2.4 2004/03/09 17:34:35 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 | */ |
| @@ -58,7 +58,7 @@ | |||
| 58 | 58 | ||
| 59 | #define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) | 59 | #define iswhite(x) test2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) |
| 60 | #define isblack(x) testbit((x)->gch.marked, BLACKBIT) | 60 | #define isblack(x) testbit((x)->gch.marked, BLACKBIT) |
| 61 | 61 | #define isgray(x) (!isblack(x) && !iswhite(x)) | |
| 62 | 62 | ||
| 63 | #define otherwhite(g) (g->currentwhite ^ bit2mask(WHITE0BIT, WHITE1BIT)) | 63 | #define otherwhite(g) (g->currentwhite ^ bit2mask(WHITE0BIT, WHITE1BIT)) |
| 64 | #define isdead(g,v) ((v)->gch.marked & otherwhite(g)) | 64 | #define isdead(g,v) ((v)->gch.marked & otherwhite(g)) |
| @@ -87,6 +87,7 @@ void luaC_sweepall (lua_State *L); | |||
| 87 | void luaC_step (lua_State *L); | 87 | void luaC_step (lua_State *L); |
| 88 | void luaC_fullgc (lua_State *L); | 88 | void luaC_fullgc (lua_State *L); |
| 89 | void luaC_link (lua_State *L, GCObject *o, lu_byte tt); | 89 | void luaC_link (lua_State *L, GCObject *o, lu_byte tt); |
| 90 | void luaC_linkupval (lua_State *L, UpVal *uv); | ||
| 90 | void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); | 91 | void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); |
| 91 | 92 | ||
| 92 | 93 | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lobject.h,v 2.2 2004/02/16 19:09:52 roberto Exp roberto $ | 2 | ** $Id: lobject.h,v 2.3 2004/02/20 16:01:05 roberto Exp roberto $ |
| 3 | ** Type definitions for Lua objects | 3 | ** Type definitions for Lua objects |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -263,7 +263,6 @@ typedef struct LocVar { | |||
| 263 | 263 | ||
| 264 | typedef struct UpVal { | 264 | typedef struct UpVal { |
| 265 | CommonHeader; | 265 | CommonHeader; |
| 266 | GCObject *gclist; | ||
| 267 | TValue *v; /* points to stack or to its own value */ | 266 | TValue *v; /* points to stack or to its own value */ |
| 268 | TValue value; /* the value (when closed) */ | 267 | TValue value; /* the value (when closed) */ |
| 269 | } UpVal; | 268 | } UpVal; |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lstate.c,v 2.2 2003/12/12 18:29:34 roberto Exp roberto $ | 2 | ** $Id: lstate.c,v 2.3 2004/02/16 19:09: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 | */ |
| @@ -93,7 +93,10 @@ static void f_luaopen (lua_State *L, void *ud) { | |||
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | 95 | ||
| 96 | static void preinit_state (lua_State *L) { | 96 | static void preinit_state (lua_State *L, global_State *g) { |
| 97 | L->l_G = g; | ||
| 98 | L->tt = LUA_TTHREAD; | ||
| 99 | L->marked = luaC_white(g); | ||
| 97 | L->stack = NULL; | 100 | L->stack = NULL; |
| 98 | L->stacksize = 0; | 101 | L->stacksize = 0; |
| 99 | L->errorJmp = NULL; | 102 | L->errorJmp = NULL; |
| @@ -116,7 +119,7 @@ static void close_state (lua_State *L) { | |||
| 116 | global_State *g = G(L); | 119 | global_State *g = G(L); |
| 117 | luaF_close(L, L->stack); /* close all upvalues for this thread */ | 120 | luaF_close(L, L->stack); /* close all upvalues for this thread */ |
| 118 | luaC_sweepall(L); /* collect all elements */ | 121 | luaC_sweepall(L); /* collect all elements */ |
| 119 | lua_assert(g->rootgc == NULL); | 122 | lua_assert(g->rootgc == obj2gco(L)); |
| 120 | luaS_freeall(L); | 123 | luaS_freeall(L); |
| 121 | luaZ_freebuffer(L, &g->buff); | 124 | luaZ_freebuffer(L, &g->buff); |
| 122 | freestack(L, L); | 125 | freestack(L, L); |
| @@ -127,9 +130,9 @@ static void close_state (lua_State *L) { | |||
| 127 | 130 | ||
| 128 | lua_State *luaE_newthread (lua_State *L) { | 131 | lua_State *luaE_newthread (lua_State *L) { |
| 129 | lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State))); | 132 | lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State))); |
| 130 | luaC_link(L, obj2gco(L1), LUA_TTHREAD); | 133 | L1->next = L->next; /* link new thread after `L' */ |
| 131 | preinit_state(L1); | 134 | L->next = obj2gco(L1); |
| 132 | L1->l_G = L->l_G; | 135 | preinit_state(L1, G(L)); |
| 133 | stack_init(L1, L); /* init stack */ | 136 | stack_init(L1, L); /* init stack */ |
| 134 | setobj2n(L, gt(L1), gt(L)); /* share table of globals */ | 137 | setobj2n(L, gt(L1), gt(L)); /* share table of globals */ |
| 135 | lua_assert(iswhite(obj2gco(L1))); | 138 | lua_assert(iswhite(obj2gco(L1))); |
| @@ -152,11 +155,9 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
| 152 | if (l == NULL) return NULL; | 155 | if (l == NULL) return NULL; |
| 153 | L = tostate(l); | 156 | L = tostate(l); |
| 154 | g = &((LG *)L)->g; | 157 | g = &((LG *)L)->g; |
| 155 | L->tt = LUA_TTHREAD; | 158 | L->next = NULL; |
| 156 | L->marked = 0; | 159 | g->currentwhite = bitmask(WHITE0BIT); |
| 157 | L->next = L->gclist = NULL; | 160 | preinit_state(L, g); |
| 158 | preinit_state(L); | ||
| 159 | L->l_G = g; | ||
| 160 | g->realloc = f; | 161 | g->realloc = f; |
| 161 | g->ud = ud; | 162 | g->ud = ud; |
| 162 | g->mainthread = L; | 163 | g->mainthread = L; |
| @@ -168,9 +169,9 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
| 168 | luaZ_initbuffer(L, &g->buff); | 169 | luaZ_initbuffer(L, &g->buff); |
| 169 | g->panic = NULL; | 170 | g->panic = NULL; |
| 170 | g->gcstate = GCSfinalize; | 171 | g->gcstate = GCSfinalize; |
| 171 | g->rootgc = NULL; | 172 | g->rootgc = obj2gco(L); |
| 172 | g->sweepstrgc = 0; | 173 | g->sweepstrgc = 0; |
| 173 | g->currentwhite = bitmask(WHITE0BIT); | 174 | g->sweepgc = &g->rootgc; |
| 174 | g->firstudata = NULL; | 175 | g->firstudata = NULL; |
| 175 | g->gray = NULL; | 176 | g->gray = NULL; |
| 176 | g->grayagain = NULL; | 177 | g->grayagain = NULL; |
