00001 /* 00002 ** $Id: lgc.c,v 2.38.1.1 2007/12/27 13:02:25 roberto Exp $ 00003 ** Garbage Collector 00004 ** See Copyright Notice in lua.h 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); /* dead key; remove it */ 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); /* udata are never gray */ 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) /* closed? */ 00087 gray2black(o); /* open upvalues are never black */ 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); /* may be marked, if left from previous GC */ 00121 reallymarkobject(g, u); 00122 } while (u != g->tmudata); 00123 } 00124 } 00125 00126 00127 /* move `dead' udata that need finalization to list `tmudata' */ 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; /* don't bother with them */ 00136 else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { 00137 markfinalized(gco2u(curr)); /* don't need finalization */ 00138 p = &curr->gch.next; 00139 } 00140 else { /* must call its gc method */ 00141 deadmem += sizeudata(gco2u(curr)); 00142 markfinalized(gco2u(curr)); 00143 *p = curr->gch.next; 00144 /* link `curr' at the end of `tmudata' list */ 00145 if (g->tmudata == NULL) /* list is empty? */ 00146 g->tmudata = curr->gch.next = curr; /* creates a circular list */ 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)) { /* is there a weak mode? */ 00167 weakkey = (strchr(svalue(mode), 'k') != NULL); 00168 weakvalue = (strchr(svalue(mode), 'v') != NULL); 00169 if (weakkey || weakvalue) { /* is really weak? */ 00170 h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ 00171 h->marked |= cast_byte((weakkey << KEYWEAKBIT) | 00172 (weakvalue << VALUEWEAKBIT)); 00173 h->gclist = g->weak; /* must be cleared after GC, ... */ 00174 g->weak = obj2gco(h); /* ... so put in the appropriate list */ 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); /* remove empty entries */ 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 ** All marks are conditional because a GC may happen while the 00201 ** prototype is still being created 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++) /* mark literals */ 00207 markvalue(g, &f->k[i]); 00208 for (i=0; i<f->sizeupvalues; i++) { /* mark upvalue names */ 00209 if (f->upvalues[i]) 00210 stringmark(f->upvalues[i]); 00211 } 00212 for (i=0; i<f->sizep; i++) { /* mark nested protos */ 00213 if (f->p[i]) 00214 markobject(g, f->p[i]); 00215 } 00216 for (i=0; i<f->sizelocvars; i++) { /* mark local-variable names */ 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++) /* mark its upvalues */ 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++) /* mark its upvalues */ 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); /* number of `ci' in use */ 00243 int s_used = cast_int(max - L->stack); /* part of stack in use */ 00244 if (L->size_ci > LUAI_MAXCALLS) /* handling overflow? */ 00245 return; /* do not touch the stacks */ 00246 if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) 00247 luaD_reallocCI(L, L->size_ci/2); /* still big enough... */ 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); /* still big enough... */ 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 ** traverse one gray object, turning it to black. 00275 ** Returns `quantity' traversed. 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)) /* table is weak? */ 00286 black2gray(o); /* keep it gray */ 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 ** The next function tells whether a key or value can be cleared from 00332 ** a weak table. Non-collectable objects are never removed from weak 00333 ** tables. Strings behave as `values', so are never removed too. for 00334 ** other objects: if really collected, cannot keep them; for userdata 00335 ** being finalized, keep them in keys, but not in values 00336 */ 00337 static int iscleared (const TValue *o, int iskey) { 00338 if (!iscollectable(o)) return 0; 00339 if (ttisstring(o)) { 00340 stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ 00341 return 0; 00342 } 00343 return iswhite(gcvalue(o)) || 00344 (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); 00345 } 00346 00347 00348 /* 00349 ** clear collected entries from weaktables 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)) /* value was collected? */ 00361 setnilvalue(o); /* remove value */ 00362 } 00363 } 00364 i = sizenode(h); 00365 while (i--) { 00366 Node *n = gnode(h, i); 00367 if (!ttisnil(gval(n)) && /* non-empty entry? */ 00368 (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) { 00369 setnilvalue(gval(n)); /* remove value ... */ 00370 removeentry(n); /* remove entry from table */ 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) /* sweep open upvalues of each thread */ 00413 sweepwholelist(L, &gco2th(curr)->openupval); 00414 if ((curr->gch.marked ^ WHITEBITS) & deadmask) { /* not dead? */ 00415 lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT)); 00416 makewhite(g, curr); /* make it white (for next cycle) */ 00417 p = &curr->gch.next; 00418 } 00419 else { /* must erase `curr' */ 00420 lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); 00421 *p = curr->gch.next; 00422 if (curr == g->rootgc) /* is the first element of the list? */ 00423 g->rootgc = curr->gch.next; /* adjust first */ 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 /* check size of string hash */ 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); /* table is too big */ 00437 /* check size of buffer */ 00438 if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ 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; /* get first element */ 00448 Udata *udata = rawgco2u(o); 00449 const TValue *tm; 00450 /* remove udata from `tmudata' */ 00451 if (o == g->tmudata) /* last element? */ 00452 g->tmudata = NULL; 00453 else 00454 g->tmudata->gch.next = udata->uv.next; 00455 udata->uv.next = g->mainthread->next; /* return it to `root' list */ 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; /* stop debug hooks during GC tag method */ 00463 g->GCthreshold = 2*g->totalbytes; /* avoid GC steps */ 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; /* restore hooks */ 00469 g->GCthreshold = oldt; /* restore threshold */ 00470 } 00471 } 00472 00473 00474 /* 00475 ** Call all GC tag methods 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); /* mask to collect all elements */ 00487 sweepwholelist(L, &g->rootgc); 00488 for (i = 0; i < g->strt.size; i++) /* free all string lists */ 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 /* mark root set */ 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 /* make global table be traversed before main stack */ 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; /* total size of userdata to be finalized */ 00528 /* remark occasional upvalues of (maybe) dead threads */ 00529 remarkupvals(g); 00530 /* traverse objects cautch by write barrier and by 'remarkupvals' */ 00531 propagateall(g); 00532 /* remark weak tables */ 00533 g->gray = g->weak; 00534 g->weak = NULL; 00535 lua_assert(!iswhite(obj2gco(g->mainthread))); 00536 markobject(g, L); /* mark running thread */ 00537 markmt(g); /* mark basic metatables (again) */ 00538 propagateall(g); 00539 /* remark gray again */ 00540 g->gray = g->grayagain; 00541 g->grayagain = NULL; 00542 propagateall(g); 00543 udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ 00544 marktmu(g); /* mark `preserved' userdata */ 00545 udsize += propagateall(g); /* remark, to propagate `preserveness' */ 00546 cleartable(g->weak); /* remove collected objects from weak tables */ 00547 /* flip current white */ 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; /* first estimate */ 00553 } 00554 00555 00556 static l_mem singlestep (lua_State *L) { 00557 global_State *g = G(L); 00558 /*lua_checkmemory(L);*/ 00559 switch (g->gcstate) { 00560 case GCSpause: { 00561 markroot(L); /* start a new collection */ 00562 return 0; 00563 } 00564 case GCSpropagate: { 00565 if (g->gray) 00566 return propagatemark(g); 00567 else { /* no more `gray' objects */ 00568 atomic(L); /* finish mark phase */ 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) /* nothing more to sweep? */ 00576 g->gcstate = GCSsweep; /* end sweep-string phase */ 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) { /* nothing more to sweep? */ 00585 checkSizes(L); 00586 g->gcstate = GCSfinalize; /* end sweep phase */ 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; /* end collection */ 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; /* no limit */ 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; /* - lim/g->gcstepmul;*/ 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 /* reset sweep marks to sweep all elements (returning them to white) */ 00640 g->sweepstrgc = 0; 00641 g->sweepgc = &g->rootgc; 00642 /* reset other collector lists */ 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 /* finish any pending sweep phase */ 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 /* must keep invariant? */ 00668 if (g->gcstate == GCSpropagate) 00669 reallymarkobject(g, v); /* restore invariant */ 00670 else /* don't mind */ 00671 makewhite(g, o); /* mark as white just to avoid other barriers */ 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); /* make table gray (again) */ 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; /* link upvalue into `rootgc' list */ 00699 g->rootgc = o; 00700 if (isgray(o)) { 00701 if (g->gcstate == GCSpropagate) { 00702 gray2black(o); /* closed upvalues need barrier */ 00703 luaC_barrier(L, uv, uv->v); 00704 } 00705 else { /* sweep phase: sweep it (turning it into white) */ 00706 makewhite(g, o); 00707 lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); 00708 } 00709 } 00710 } 00711
ContextLogger2—ContextLogger2 Logger Daemon Internals—Generated on Mon May 2 13:49:54 2011 by Doxygen 1.6.1