00001
00002
00003
00004
00005
00006
00007 #include <string.h>
00008
00009 #define lgc_c
00010 #define LUA_CORE
00011
00012 #include "lua.h"
00013
00014 #include "ldebug.h"
00015 #include "ldo.h"
00016 #include "lfunc.h"
00017 #include "lgc.h"
00018 #include "lmem.h"
00019 #include "lobject.h"
00020 #include "lstate.h"
00021 #include "lstring.h"
00022 #include "ltable.h"
00023 #include "ltm.h"
00024
00025
00026 #define GCSTEPSIZE 1024u
00027 #define GCSWEEPMAX 40
00028 #define GCSWEEPCOST 10
00029 #define GCFINALIZECOST 100
00030
00031
00032 #define maskmarks cast_byte(~(bitmask(BLACKBIT)|WHITEBITS))
00033
00034 #define makewhite(g,x) \
00035 ((x)->gch.marked = cast_byte(((x)->gch.marked & maskmarks) | luaC_white(g)))
00036
00037 #define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT)
00038 #define black2gray(x) resetbit((x)->gch.marked, BLACKBIT)
00039
00040 #define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT)
00041
00042
00043 #define isfinalized(u) testbit((u)->marked, FINALIZEDBIT)
00044 #define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT)
00045
00046
00047 #define KEYWEAK bitmask(KEYWEAKBIT)
00048 #define VALUEWEAK bitmask(VALUEWEAKBIT)
00049
00050
00051
00052 #define markvalue(g,o) { checkconsistency(o); \
00053 if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); }
00054
00055 #define markobject(g,t) { if (iswhite(obj2gco(t))) \
00056 reallymarkobject(g, obj2gco(t)); }
00057
00058
00059 #define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause)
00060
00061
00062 static void removeentry (Node *n) {
00063 lua_assert(ttisnil(gval(n)));
00064 if (iscollectable(gkey(n)))
00065 setttype(gkey(n), LUA_TDEADKEY);
00066 }
00067
00068
00069 static void reallymarkobject (global_State *g, GCObject *o) {
00070 lua_assert(iswhite(o) && !isdead(g, o));
00071 white2gray(o);
00072 switch (o->gch.tt) {
00073 case LUA_TSTRING: {
00074 return;
00075 }
00076 case LUA_TUSERDATA: {
00077 Table *mt = gco2u(o)->metatable;
00078 gray2black(o);
00079 if (mt) markobject(g, mt);
00080 markobject(g, gco2u(o)->env);
00081 return;
00082 }
00083 case LUA_TUPVAL: {
00084 UpVal *uv = gco2uv(o);
00085 markvalue(g, uv->v);
00086 if (uv->v == &uv->u.value)
00087 gray2black(o);
00088 return;
00089 }
00090 case LUA_TFUNCTION: {
00091 gco2cl(o)->c.gclist = g->gray;
00092 g->gray = o;
00093 break;
00094 }
00095 case LUA_TTABLE: {
00096 gco2h(o)->gclist = g->gray;
00097 g->gray = o;
00098 break;
00099 }
00100 case LUA_TTHREAD: {
00101 gco2th(o)->gclist = g->gray;
00102 g->gray = o;
00103 break;
00104 }
00105 case LUA_TPROTO: {
00106 gco2p(o)->gclist = g->gray;
00107 g->gray = o;
00108 break;
00109 }
00110 default: lua_assert(0);
00111 }
00112 }
00113
00114
00115 static void marktmu (global_State *g) {
00116 GCObject *u = g->tmudata;
00117 if (u) {
00118 do {
00119 u = u->gch.next;
00120 makewhite(g, u);
00121 reallymarkobject(g, u);
00122 } while (u != g->tmudata);
00123 }
00124 }
00125
00126
00127
00128 size_t luaC_separateudata (lua_State *L, int all) {
00129 global_State *g = G(L);
00130 size_t deadmem = 0;
00131 GCObject **p = &g->mainthread->next;
00132 GCObject *curr;
00133 while ((curr = *p) != NULL) {
00134 if (!(iswhite(curr) || all) || isfinalized(gco2u(curr)))
00135 p = &curr->gch.next;
00136 else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) {
00137 markfinalized(gco2u(curr));
00138 p = &curr->gch.next;
00139 }
00140 else {
00141 deadmem += sizeudata(gco2u(curr));
00142 markfinalized(gco2u(curr));
00143 *p = curr->gch.next;
00144
00145 if (g->tmudata == NULL)
00146 g->tmudata = curr->gch.next = curr;
00147 else {
00148 curr->gch.next = g->tmudata->gch.next;
00149 g->tmudata->gch.next = curr;
00150 g->tmudata = curr;
00151 }
00152 }
00153 }
00154 return deadmem;
00155 }
00156
00157
00158 static int traversetable (global_State *g, Table *h) {
00159 int i;
00160 int weakkey = 0;
00161 int weakvalue = 0;
00162 const TValue *mode;
00163 if (h->metatable)
00164 markobject(g, h->metatable);
00165 mode = gfasttm(g, h->metatable, TM_MODE);
00166 if (mode && ttisstring(mode)) {
00167 weakkey = (strchr(svalue(mode), 'k') != NULL);
00168 weakvalue = (strchr(svalue(mode), 'v') != NULL);
00169 if (weakkey || weakvalue) {
00170 h->marked &= ~(KEYWEAK | VALUEWEAK);
00171 h->marked |= cast_byte((weakkey << KEYWEAKBIT) |
00172 (weakvalue << VALUEWEAKBIT));
00173 h->gclist = g->weak;
00174 g->weak = obj2gco(h);
00175 }
00176 }
00177 if (weakkey && weakvalue) return 1;
00178 if (!weakvalue) {
00179 i = h->sizearray;
00180 while (i--)
00181 markvalue(g, &h->array[i]);
00182 }
00183 i = sizenode(h);
00184 while (i--) {
00185 Node *n = gnode(h, i);
00186 lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n)));
00187 if (ttisnil(gval(n)))
00188 removeentry(n);
00189 else {
00190 lua_assert(!ttisnil(gkey(n)));
00191 if (!weakkey) markvalue(g, gkey(n));
00192 if (!weakvalue) markvalue(g, gval(n));
00193 }
00194 }
00195 return weakkey || weakvalue;
00196 }
00197
00198
00199
00200
00201
00202
00203 static void traverseproto (global_State *g, Proto *f) {
00204 int i;
00205 if (f->source) stringmark(f->source);
00206 for (i=0; i<f->sizek; i++)
00207 markvalue(g, &f->k[i]);
00208 for (i=0; i<f->sizeupvalues; i++) {
00209 if (f->upvalues[i])
00210 stringmark(f->upvalues[i]);
00211 }
00212 for (i=0; i<f->sizep; i++) {
00213 if (f->p[i])
00214 markobject(g, f->p[i]);
00215 }
00216 for (i=0; i<f->sizelocvars; i++) {
00217 if (f->locvars[i].varname)
00218 stringmark(f->locvars[i].varname);
00219 }
00220 }
00221
00222
00223
00224 static void traverseclosure (global_State *g, Closure *cl) {
00225 markobject(g, cl->c.env);
00226 if (cl->c.isC) {
00227 int i;
00228 for (i=0; i<cl->c.nupvalues; i++)
00229 markvalue(g, &cl->c.upvalue[i]);
00230 }
00231 else {
00232 int i;
00233 lua_assert(cl->l.nupvalues == cl->l.p->nups);
00234 markobject(g, cl->l.p);
00235 for (i=0; i<cl->l.nupvalues; i++)
00236 markobject(g, cl->l.upvals[i]);
00237 }
00238 }
00239
00240
00241 static void checkstacksizes (lua_State *L, StkId max) {
00242 int ci_used = cast_int(L->ci - L->base_ci);
00243 int s_used = cast_int(max - L->stack);
00244 if (L->size_ci > LUAI_MAXCALLS)
00245 return;
00246 if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci)
00247 luaD_reallocCI(L, L->size_ci/2);
00248 condhardstacktests(luaD_reallocCI(L, ci_used + 1));
00249 if (4*s_used < L->stacksize &&
00250 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize)
00251 luaD_reallocstack(L, L->stacksize/2);
00252 condhardstacktests(luaD_reallocstack(L, s_used));
00253 }
00254
00255
00256 static void traversestack (global_State *g, lua_State *l) {
00257 StkId o, lim;
00258 CallInfo *ci;
00259 markvalue(g, gt(l));
00260 lim = l->top;
00261 for (ci = l->base_ci; ci <= l->ci; ci++) {
00262 lua_assert(ci->top <= l->stack_last);
00263 if (lim < ci->top) lim = ci->top;
00264 }
00265 for (o = l->stack; o < l->top; o++)
00266 markvalue(g, o);
00267 for (; o <= lim; o++)
00268 setnilvalue(o);
00269 checkstacksizes(l, lim);
00270 }
00271
00272
00273
00274
00275
00276
00277 static l_mem propagatemark (global_State *g) {
00278 GCObject *o = g->gray;
00279 lua_assert(isgray(o));
00280 gray2black(o);
00281 switch (o->gch.tt) {
00282 case LUA_TTABLE: {
00283 Table *h = gco2h(o);
00284 g->gray = h->gclist;
00285 if (traversetable(g, h))
00286 black2gray(o);
00287 return sizeof(Table) + sizeof(TValue) * h->sizearray +
00288 sizeof(Node) * sizenode(h);
00289 }
00290 case LUA_TFUNCTION: {
00291 Closure *cl = gco2cl(o);
00292 g->gray = cl->c.gclist;
00293 traverseclosure(g, cl);
00294 return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) :
00295 sizeLclosure(cl->l.nupvalues);
00296 }
00297 case LUA_TTHREAD: {
00298 lua_State *th = gco2th(o);
00299 g->gray = th->gclist;
00300 th->gclist = g->grayagain;
00301 g->grayagain = o;
00302 black2gray(o);
00303 traversestack(g, th);
00304 return sizeof(lua_State) + sizeof(TValue) * th->stacksize +
00305 sizeof(CallInfo) * th->size_ci;
00306 }
00307 case LUA_TPROTO: {
00308 Proto *p = gco2p(o);
00309 g->gray = p->gclist;
00310 traverseproto(g, p);
00311 return sizeof(Proto) + sizeof(Instruction) * p->sizecode +
00312 sizeof(Proto *) * p->sizep +
00313 sizeof(TValue) * p->sizek +
00314 sizeof(int) * p->sizelineinfo +
00315 sizeof(LocVar) * p->sizelocvars +
00316 sizeof(TString *) * p->sizeupvalues;
00317 }
00318 default: lua_assert(0); return 0;
00319 }
00320 }
00321
00322
00323 static size_t propagateall (global_State *g) {
00324 size_t m = 0;
00325 while (g->gray) m += propagatemark(g);
00326 return m;
00327 }
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337 static int iscleared (const TValue *o, int iskey) {
00338 if (!iscollectable(o)) return 0;
00339 if (ttisstring(o)) {
00340 stringmark(rawtsvalue(o));
00341 return 0;
00342 }
00343 return iswhite(gcvalue(o)) ||
00344 (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o))));
00345 }
00346
00347
00348
00349
00350
00351 static void cleartable (GCObject *l) {
00352 while (l) {
00353 Table *h = gco2h(l);
00354 int i = h->sizearray;
00355 lua_assert(testbit(h->marked, VALUEWEAKBIT) ||
00356 testbit(h->marked, KEYWEAKBIT));
00357 if (testbit(h->marked, VALUEWEAKBIT)) {
00358 while (i--) {
00359 TValue *o = &h->array[i];
00360 if (iscleared(o, 0))
00361 setnilvalue(o);
00362 }
00363 }
00364 i = sizenode(h);
00365 while (i--) {
00366 Node *n = gnode(h, i);
00367 if (!ttisnil(gval(n)) &&
00368 (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) {
00369 setnilvalue(gval(n));
00370 removeentry(n);
00371 }
00372 }
00373 l = h->gclist;
00374 }
00375 }
00376
00377
00378 static void freeobj (lua_State *L, GCObject *o) {
00379 switch (o->gch.tt) {
00380 case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break;
00381 case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break;
00382 case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break;
00383 case LUA_TTABLE: luaH_free(L, gco2h(o)); break;
00384 case LUA_TTHREAD: {
00385 lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread);
00386 luaE_freethread(L, gco2th(o));
00387 break;
00388 }
00389 case LUA_TSTRING: {
00390 G(L)->strt.nuse--;
00391 luaM_freemem(L, o, sizestring(gco2ts(o)));
00392 break;
00393 }
00394 case LUA_TUSERDATA: {
00395 luaM_freemem(L, o, sizeudata(gco2u(o)));
00396 break;
00397 }
00398 default: lua_assert(0);
00399 }
00400 }
00401
00402
00403
00404 #define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM)
00405
00406
00407 static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
00408 GCObject *curr;
00409 global_State *g = G(L);
00410 int deadmask = otherwhite(g);
00411 while ((curr = *p) != NULL && count-- > 0) {
00412 if (curr->gch.tt == LUA_TTHREAD)
00413 sweepwholelist(L, &gco2th(curr)->openupval);
00414 if ((curr->gch.marked ^ WHITEBITS) & deadmask) {
00415 lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT));
00416 makewhite(g, curr);
00417 p = &curr->gch.next;
00418 }
00419 else {
00420 lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT));
00421 *p = curr->gch.next;
00422 if (curr == g->rootgc)
00423 g->rootgc = curr->gch.next;
00424 freeobj(L, curr);
00425 }
00426 }
00427 return p;
00428 }
00429
00430
00431 static void checkSizes (lua_State *L) {
00432 global_State *g = G(L);
00433
00434 if (g->strt.nuse < cast(lu_int32, g->strt.size/4) &&
00435 g->strt.size > MINSTRTABSIZE*2)
00436 luaS_resize(L, g->strt.size/2);
00437
00438 if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) {
00439 size_t newsize = luaZ_sizebuffer(&g->buff) / 2;
00440 luaZ_resizebuffer(L, &g->buff, newsize);
00441 }
00442 }
00443
00444
00445 static void GCTM (lua_State *L) {
00446 global_State *g = G(L);
00447 GCObject *o = g->tmudata->gch.next;
00448 Udata *udata = rawgco2u(o);
00449 const TValue *tm;
00450
00451 if (o == g->tmudata)
00452 g->tmudata = NULL;
00453 else
00454 g->tmudata->gch.next = udata->uv.next;
00455 udata->uv.next = g->mainthread->next;
00456 g->mainthread->next = o;
00457 makewhite(g, o);
00458 tm = fasttm(L, udata->uv.metatable, TM_GC);
00459 if (tm != NULL) {
00460 lu_byte oldah = L->allowhook;
00461 lu_mem oldt = g->GCthreshold;
00462 L->allowhook = 0;
00463 g->GCthreshold = 2*g->totalbytes;
00464 setobj2s(L, L->top, tm);
00465 setuvalue(L, L->top+1, udata);
00466 L->top += 2;
00467 luaD_call(L, L->top - 2, 0);
00468 L->allowhook = oldah;
00469 g->GCthreshold = oldt;
00470 }
00471 }
00472
00473
00474
00475
00476
00477 void luaC_callGCTM (lua_State *L) {
00478 while (G(L)->tmudata)
00479 GCTM(L);
00480 }
00481
00482
00483 void luaC_freeall (lua_State *L) {
00484 global_State *g = G(L);
00485 int i;
00486 g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT);
00487 sweepwholelist(L, &g->rootgc);
00488 for (i = 0; i < g->strt.size; i++)
00489 sweepwholelist(L, &g->strt.hash[i]);
00490 }
00491
00492
00493 static void markmt (global_State *g) {
00494 int i;
00495 for (i=0; i<NUM_TAGS; i++)
00496 if (g->mt[i]) markobject(g, g->mt[i]);
00497 }
00498
00499
00500
00501 static void markroot (lua_State *L) {
00502 global_State *g = G(L);
00503 g->gray = NULL;
00504 g->grayagain = NULL;
00505 g->weak = NULL;
00506 markobject(g, g->mainthread);
00507
00508 markvalue(g, gt(g->mainthread));
00509 markvalue(g, registry(L));
00510 markmt(g);
00511 g->gcstate = GCSpropagate;
00512 }
00513
00514
00515 static void remarkupvals (global_State *g) {
00516 UpVal *uv;
00517 for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) {
00518 lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
00519 if (isgray(obj2gco(uv)))
00520 markvalue(g, uv->v);
00521 }
00522 }
00523
00524
00525 static void atomic (lua_State *L) {
00526 global_State *g = G(L);
00527 size_t udsize;
00528
00529 remarkupvals(g);
00530
00531 propagateall(g);
00532
00533 g->gray = g->weak;
00534 g->weak = NULL;
00535 lua_assert(!iswhite(obj2gco(g->mainthread)));
00536 markobject(g, L);
00537 markmt(g);
00538 propagateall(g);
00539
00540 g->gray = g->grayagain;
00541 g->grayagain = NULL;
00542 propagateall(g);
00543 udsize = luaC_separateudata(L, 0);
00544 marktmu(g);
00545 udsize += propagateall(g);
00546 cleartable(g->weak);
00547
00548 g->currentwhite = cast_byte(otherwhite(g));
00549 g->sweepstrgc = 0;
00550 g->sweepgc = &g->rootgc;
00551 g->gcstate = GCSsweepstring;
00552 g->estimate = g->totalbytes - udsize;
00553 }
00554
00555
00556 static l_mem singlestep (lua_State *L) {
00557 global_State *g = G(L);
00558
00559 switch (g->gcstate) {
00560 case GCSpause: {
00561 markroot(L);
00562 return 0;
00563 }
00564 case GCSpropagate: {
00565 if (g->gray)
00566 return propagatemark(g);
00567 else {
00568 atomic(L);
00569 return 0;
00570 }
00571 }
00572 case GCSsweepstring: {
00573 lu_mem old = g->totalbytes;
00574 sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
00575 if (g->sweepstrgc >= g->strt.size)
00576 g->gcstate = GCSsweep;
00577 lua_assert(old >= g->totalbytes);
00578 g->estimate -= old - g->totalbytes;
00579 return GCSWEEPCOST;
00580 }
00581 case GCSsweep: {
00582 lu_mem old = g->totalbytes;
00583 g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
00584 if (*g->sweepgc == NULL) {
00585 checkSizes(L);
00586 g->gcstate = GCSfinalize;
00587 }
00588 lua_assert(old >= g->totalbytes);
00589 g->estimate -= old - g->totalbytes;
00590 return GCSWEEPMAX*GCSWEEPCOST;
00591 }
00592 case GCSfinalize: {
00593 if (g->tmudata) {
00594 GCTM(L);
00595 if (g->estimate > GCFINALIZECOST)
00596 g->estimate -= GCFINALIZECOST;
00597 return GCFINALIZECOST;
00598 }
00599 else {
00600 g->gcstate = GCSpause;
00601 g->gcdept = 0;
00602 return 0;
00603 }
00604 }
00605 default: lua_assert(0); return 0;
00606 }
00607 }
00608
00609
00610 void luaC_step (lua_State *L) {
00611 global_State *g = G(L);
00612 l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul;
00613 if (lim == 0)
00614 lim = (MAX_LUMEM-1)/2;
00615 g->gcdept += g->totalbytes - g->GCthreshold;
00616 do {
00617 lim -= singlestep(L);
00618 if (g->gcstate == GCSpause)
00619 break;
00620 } while (lim > 0);
00621 if (g->gcstate != GCSpause) {
00622 if (g->gcdept < GCSTEPSIZE)
00623 g->GCthreshold = g->totalbytes + GCSTEPSIZE;
00624 else {
00625 g->gcdept -= GCSTEPSIZE;
00626 g->GCthreshold = g->totalbytes;
00627 }
00628 }
00629 else {
00630 lua_assert(g->totalbytes >= g->estimate);
00631 setthreshold(g);
00632 }
00633 }
00634
00635
00636 void luaC_fullgc (lua_State *L) {
00637 global_State *g = G(L);
00638 if (g->gcstate <= GCSpropagate) {
00639
00640 g->sweepstrgc = 0;
00641 g->sweepgc = &g->rootgc;
00642
00643 g->gray = NULL;
00644 g->grayagain = NULL;
00645 g->weak = NULL;
00646 g->gcstate = GCSsweepstring;
00647 }
00648 lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate);
00649
00650 while (g->gcstate != GCSfinalize) {
00651 lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep);
00652 singlestep(L);
00653 }
00654 markroot(L);
00655 while (g->gcstate != GCSpause) {
00656 singlestep(L);
00657 }
00658 setthreshold(g);
00659 }
00660
00661
00662 void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
00663 global_State *g = G(L);
00664 lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
00665 lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
00666 lua_assert(ttype(&o->gch) != LUA_TTABLE);
00667
00668 if (g->gcstate == GCSpropagate)
00669 reallymarkobject(g, v);
00670 else
00671 makewhite(g, o);
00672 }
00673
00674
00675 void luaC_barrierback (lua_State *L, Table *t) {
00676 global_State *g = G(L);
00677 GCObject *o = obj2gco(t);
00678 lua_assert(isblack(o) && !isdead(g, o));
00679 lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
00680 black2gray(o);
00681 t->gclist = g->grayagain;
00682 g->grayagain = o;
00683 }
00684
00685
00686 void luaC_link (lua_State *L, GCObject *o, lu_byte tt) {
00687 global_State *g = G(L);
00688 o->gch.next = g->rootgc;
00689 g->rootgc = o;
00690 o->gch.marked = luaC_white(g);
00691 o->gch.tt = tt;
00692 }
00693
00694
00695 void luaC_linkupval (lua_State *L, UpVal *uv) {
00696 global_State *g = G(L);
00697 GCObject *o = obj2gco(uv);
00698 o->gch.next = g->rootgc;
00699 g->rootgc = o;
00700 if (isgray(o)) {
00701 if (g->gcstate == GCSpropagate) {
00702 gray2black(o);
00703 luaC_barrier(L, uv, uv->v);
00704 }
00705 else {
00706 makewhite(g, o);
00707 lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
00708 }
00709 }
00710 }