1139749Simp/* $NetBSD$ */ 2182159Snyan 3119822Simp/* 4119822Simp** Id: lgc.c,v 2.38.1.1 2007/12/27 13:02:25 roberto Exp 5119822Simp** Garbage Collector 6119822Simp** See Copyright Notice in lua.h 7119822Simp*/ 8119822Simp 9119822Simp#include <string.h> 10119822Simp 11119822Simp#define lgc_c 12119822Simp#define LUA_CORE 13119822Simp 14119822Simp#include "lua.h" 15119822Simp 16119822Simp#include "ldebug.h" 17119822Simp#include "ldo.h" 18119822Simp#include "lfunc.h" 19119822Simp#include "lgc.h" 20119822Simp#include "lmem.h" 21119822Simp#include "lobject.h" 22119822Simp#include "lstate.h" 23119822Simp#include "lstring.h" 24119822Simp#include "ltable.h" 25119822Simp#include "ltm.h" 26119822Simp 27119822Simp 28119822Simp#define GCSTEPSIZE 1024u 29119822Simp#define GCSWEEPMAX 40 30119822Simp#define GCSWEEPCOST 10 31119822Simp#define GCFINALIZECOST 100 32119822Simp 33119822Simp 34119822Simp#define maskmarks cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) 35119822Simp 36119822Simp#define makewhite(g,x) \ 37119822Simp ((x)->gch.marked = cast_byte(((x)->gch.marked & maskmarks) | luaC_white(g))) 38119822Simp 39119822Simp#define white2gray(x) reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT) 40216592Stijl#define black2gray(x) resetbit((x)->gch.marked, BLACKBIT) 41216592Stijl 42127215Smarcel#define stringmark(s) reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT) 43182159Snyan 44182159Snyan 45182159Snyan#define isfinalized(u) testbit((u)->marked, FINALIZEDBIT) 46182159Snyan#define markfinalized(u) l_setbit((u)->marked, FINALIZEDBIT) 47182159Snyan 48182159Snyan 49182159Snyan#define KEYWEAK bitmask(KEYWEAKBIT) 50182159Snyan#define VALUEWEAK bitmask(VALUEWEAKBIT) 51182159Snyan 52182159Snyan 53182159Snyan 54182159Snyan#define markvalue(g,o) { checkconsistency(o); \ 55182159Snyan if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } 56182159Snyan 57182159Snyan#define markobject(g,t) { if (iswhite(obj2gco(t))) \ 58182159Snyan reallymarkobject(g, obj2gco(t)); } 59182159Snyan 60182159Snyan 61182159Snyan#define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause) 62182159Snyan 63119822Simp 64119866Smarcelstatic void removeentry (Node *n) { 65119866Smarcel lua_assert(ttisnil(gval(n))); 66119866Smarcel if (iscollectable(gkey(n))) 67182837Snyan setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */ 68182159Snyan} 69182159Snyan 70182159Snyan 71119866Smarcelstatic void reallymarkobject (global_State *g, GCObject *o) { 72119866Smarcel lua_assert(iswhite(o) && !isdead(g, o)); 73119866Smarcel white2gray(o); 74119822Simp switch (o->gch.tt) { 75119822Simp case LUA_TSTRING: { 76168281Smarcel return; 77182159Snyan } 78119822Simp case LUA_TUSERDATA: { 79168281Smarcel Table *mt = gco2u(o)->metatable; 80168281Smarcel gray2black(o); /* udata are never gray */ 81168281Smarcel if (mt) markobject(g, mt); 82168281Smarcel markobject(g, gco2u(o)->env); 83127215Smarcel return; 84168281Smarcel } 85127215Smarcel case LUA_TUPVAL: { 86127215Smarcel UpVal *uv = gco2uv(o); 87119822Simp markvalue(g, uv->v); 88129276Snyan if (uv->v == &uv->u.value) /* closed? */ 89129276Snyan gray2black(o); /* open upvalues are never black */ 90182159Snyan return; 91119822Simp } 92182159Snyan case LUA_TFUNCTION: { 93182159Snyan gco2cl(o)->c.gclist = g->gray; 94119822Simp g->gray = o; 95182159Snyan break; 96119822Simp } 97182159Snyan case LUA_TTABLE: { 98119822Simp gco2h(o)->gclist = g->gray; 99119822Simp g->gray = o; 100119822Simp break; 101119822Simp } 102119822Simp case LUA_TTHREAD: { 103119822Simp gco2th(o)->gclist = g->gray; 104119822Simp g->gray = o; 105119822Simp break; 106119822Simp } 107119822Simp case LUA_TPROTO: { 108119822Simp gco2p(o)->gclist = g->gray; 109137972Snyan g->gray = o; 110182159Snyan break; 111182159Snyan } 112182159Snyan default: lua_assert(0); 113182159Snyan } 114168281Smarcel} 115120452Smarcel 116127215Smarcel 117168281Smarcelstatic void marktmu (global_State *g) { 118168281Smarcel GCObject *u = g->tmudata; 119120381Snyan if (u) { 120119822Simp do { 121119822Simp u = u->gch.next; 122119822Simp makewhite(g, u); /* may be marked, if left from previous GC */ 123119822Simp reallymarkobject(g, u); 124119822Simp } while (u != g->tmudata); 125119822Simp } 126119822Simp} 127119822Simp 128119822Simp 129119822Simp/* move `dead' udata that need finalization to list `tmudata' */ 130119822Simpsize_t luaC_separateudata (lua_State *L, int all) { 131119822Simp global_State *g = G(L); 132119822Simp size_t deadmem = 0; 133 GCObject **p = &g->mainthread->next; 134 GCObject *curr; 135 while ((curr = *p) != NULL) { 136 if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) 137 p = &curr->gch.next; /* don't bother with them */ 138 else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { 139 markfinalized(gco2u(curr)); /* don't need finalization */ 140 p = &curr->gch.next; 141 } 142 else { /* must call its gc method */ 143 deadmem += sizeudata(gco2u(curr)); 144 markfinalized(gco2u(curr)); 145 *p = curr->gch.next; 146 /* link `curr' at the end of `tmudata' list */ 147 if (g->tmudata == NULL) /* list is empty? */ 148 g->tmudata = curr->gch.next = curr; /* creates a circular list */ 149 else { 150 curr->gch.next = g->tmudata->gch.next; 151 g->tmudata->gch.next = curr; 152 g->tmudata = curr; 153 } 154 } 155 } 156 return deadmem; 157} 158 159 160static int traversetable (global_State *g, Table *h) { 161 int i; 162 int weakkey = 0; 163 int weakvalue = 0; 164 const TValue *mode; 165 if (h->metatable) 166 markobject(g, h->metatable); 167 mode = gfasttm(g, h->metatable, TM_MODE); 168 if (mode && ttisstring(mode)) { /* is there a weak mode? */ 169 weakkey = (strchr(svalue(mode), 'k') != NULL); 170 weakvalue = (strchr(svalue(mode), 'v') != NULL); 171 if (weakkey || weakvalue) { /* is really weak? */ 172 h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ 173 h->marked |= cast_byte((weakkey << KEYWEAKBIT) | 174 (weakvalue << VALUEWEAKBIT)); 175 h->gclist = g->weak; /* must be cleared after GC, ... */ 176 g->weak = obj2gco(h); /* ... so put in the appropriate list */ 177 } 178 } 179 if (weakkey && weakvalue) return 1; 180 if (!weakvalue) { 181 i = h->sizearray; 182 while (i--) 183 markvalue(g, &h->array[i]); 184 } 185 i = sizenode(h); 186 while (i--) { 187 Node *n = gnode(h, i); 188 lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); 189 if (ttisnil(gval(n))) 190 removeentry(n); /* remove empty entries */ 191 else { 192 lua_assert(!ttisnil(gkey(n))); 193 if (!weakkey) markvalue(g, gkey(n)); 194 if (!weakvalue) markvalue(g, gval(n)); 195 } 196 } 197 return weakkey || weakvalue; 198} 199 200 201/* 202** All marks are conditional because a GC may happen while the 203** prototype is still being created 204*/ 205static void traverseproto (global_State *g, Proto *f) { 206 int i; 207 if (f->source) stringmark(f->source); 208 for (i=0; i<f->sizek; i++) /* mark literals */ 209 markvalue(g, &f->k[i]); 210 for (i=0; i<f->sizeupvalues; i++) { /* mark upvalue names */ 211 if (f->upvalues[i]) 212 stringmark(f->upvalues[i]); 213 } 214 for (i=0; i<f->sizep; i++) { /* mark nested protos */ 215 if (f->p[i]) 216 markobject(g, f->p[i]); 217 } 218 for (i=0; i<f->sizelocvars; i++) { /* mark local-variable names */ 219 if (f->locvars[i].varname) 220 stringmark(f->locvars[i].varname); 221 } 222} 223 224 225 226static void traverseclosure (global_State *g, Closure *cl) { 227 markobject(g, cl->c.env); 228 if (cl->c.isC) { 229 int i; 230 for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */ 231 markvalue(g, &cl->c.upvalue[i]); 232 } 233 else { 234 int i; 235 lua_assert(cl->l.nupvalues == cl->l.p->nups); 236 markobject(g, cl->l.p); 237 for (i=0; i<cl->l.nupvalues; i++) /* mark its upvalues */ 238 markobject(g, cl->l.upvals[i]); 239 } 240} 241 242 243static void checkstacksizes (lua_State *L, StkId max) { 244 int ci_used = cast_int(L->ci - L->base_ci); /* number of `ci' in use */ 245 int s_used = cast_int(max - L->stack); /* part of stack in use */ 246 if (L->size_ci > LUAI_MAXCALLS) /* handling overflow? */ 247 return; /* do not touch the stacks */ 248 if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) 249 luaD_reallocCI(L, L->size_ci/2); /* still big enough... */ 250 condhardstacktests(luaD_reallocCI(L, ci_used + 1)); 251 if (4*s_used < L->stacksize && 252 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize) 253 luaD_reallocstack(L, L->stacksize/2); /* still big enough... */ 254 condhardstacktests(luaD_reallocstack(L, s_used)); 255} 256 257 258static void traversestack (global_State *g, lua_State *l) { 259 StkId o, lim; 260 CallInfo *ci; 261 markvalue(g, gt(l)); 262 lim = l->top; 263 for (ci = l->base_ci; ci <= l->ci; ci++) { 264 lua_assert(ci->top <= l->stack_last); 265 if (lim < ci->top) lim = ci->top; 266 } 267 for (o = l->stack; o < l->top; o++) 268 markvalue(g, o); 269 for (; o <= lim; o++) 270 setnilvalue(o); 271 checkstacksizes(l, lim); 272} 273 274 275/* 276** traverse one gray object, turning it to black. 277** Returns `quantity' traversed. 278*/ 279static l_mem propagatemark (global_State *g) { 280 GCObject *o = g->gray; 281 lua_assert(isgray(o)); 282 gray2black(o); 283 switch (o->gch.tt) { 284 case LUA_TTABLE: { 285 Table *h = gco2h(o); 286 g->gray = h->gclist; 287 if (traversetable(g, h)) /* table is weak? */ 288 black2gray(o); /* keep it gray */ 289 return sizeof(Table) + sizeof(TValue) * h->sizearray + 290 sizeof(Node) * sizenode(h); 291 } 292 case LUA_TFUNCTION: { 293 Closure *cl = gco2cl(o); 294 g->gray = cl->c.gclist; 295 traverseclosure(g, cl); 296 return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : 297 sizeLclosure(cl->l.nupvalues); 298 } 299 case LUA_TTHREAD: { 300 lua_State *th = gco2th(o); 301 g->gray = th->gclist; 302 th->gclist = g->grayagain; 303 g->grayagain = o; 304 black2gray(o); 305 traversestack(g, th); 306 return sizeof(lua_State) + sizeof(TValue) * th->stacksize + 307 sizeof(CallInfo) * th->size_ci; 308 } 309 case LUA_TPROTO: { 310 Proto *p = gco2p(o); 311 g->gray = p->gclist; 312 traverseproto(g, p); 313 return sizeof(Proto) + sizeof(Instruction) * p->sizecode + 314 sizeof(Proto *) * p->sizep + 315 sizeof(TValue) * p->sizek + 316 sizeof(int) * p->sizelineinfo + 317 sizeof(LocVar) * p->sizelocvars + 318 sizeof(TString *) * p->sizeupvalues; 319 } 320 default: lua_assert(0); return 0; 321 } 322} 323 324 325static size_t propagateall (global_State *g) { 326 size_t m = 0; 327 while (g->gray) m += propagatemark(g); 328 return m; 329} 330 331 332/* 333** The next function tells whether a key or value can be cleared from 334** a weak table. Non-collectable objects are never removed from weak 335** tables. Strings behave as `values', so are never removed too. for 336** other objects: if really collected, cannot keep them; for userdata 337** being finalized, keep them in keys, but not in values 338*/ 339static int iscleared (const TValue *o, int iskey) { 340 if (!iscollectable(o)) return 0; 341 if (ttisstring(o)) { 342 stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ 343 return 0; 344 } 345 return iswhite(gcvalue(o)) || 346 (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); 347} 348 349 350/* 351** clear collected entries from weaktables 352*/ 353static void cleartable (GCObject *l) { 354 while (l) { 355 Table *h = gco2h(l); 356 int i = h->sizearray; 357 lua_assert(testbit(h->marked, VALUEWEAKBIT) || 358 testbit(h->marked, KEYWEAKBIT)); 359 if (testbit(h->marked, VALUEWEAKBIT)) { 360 while (i--) { 361 TValue *o = &h->array[i]; 362 if (iscleared(o, 0)) /* value was collected? */ 363 setnilvalue(o); /* remove value */ 364 } 365 } 366 i = sizenode(h); 367 while (i--) { 368 Node *n = gnode(h, i); 369 if (!ttisnil(gval(n)) && /* non-empty entry? */ 370 (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) { 371 setnilvalue(gval(n)); /* remove value ... */ 372 removeentry(n); /* remove entry from table */ 373 } 374 } 375 l = h->gclist; 376 } 377} 378 379 380static void freeobj (lua_State *L, GCObject *o) { 381 switch (o->gch.tt) { 382 case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; 383 case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; 384 case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; 385 case LUA_TTABLE: luaH_free(L, gco2h(o)); break; 386 case LUA_TTHREAD: { 387 lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread); 388 luaE_freethread(L, gco2th(o)); 389 break; 390 } 391 case LUA_TSTRING: { 392 G(L)->strt.nuse--; 393 luaM_freemem(L, o, sizestring(gco2ts(o))); 394 break; 395 } 396 case LUA_TUSERDATA: { 397 luaM_freemem(L, o, sizeudata(gco2u(o))); 398 break; 399 } 400 default: lua_assert(0); 401 } 402} 403 404 405 406#define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) 407 408 409static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { 410 GCObject *curr; 411 global_State *g = G(L); 412 int deadmask = otherwhite(g); 413 while ((curr = *p) != NULL && count-- > 0) { 414 if (curr->gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */ 415 sweepwholelist(L, &gco2th(curr)->openupval); 416 if ((curr->gch.marked ^ WHITEBITS) & deadmask) { /* not dead? */ 417 lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT)); 418 makewhite(g, curr); /* make it white (for next cycle) */ 419 p = &curr->gch.next; 420 } 421 else { /* must erase `curr' */ 422 lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); 423 *p = curr->gch.next; 424 if (curr == g->rootgc) /* is the first element of the list? */ 425 g->rootgc = curr->gch.next; /* adjust first */ 426 freeobj(L, curr); 427 } 428 } 429 return p; 430} 431 432 433static void checkSizes (lua_State *L) { 434 global_State *g = G(L); 435 /* check size of string hash */ 436 if (g->strt.nuse < cast(lu_int32, g->strt.size/4) && 437 g->strt.size > MINSTRTABSIZE*2) 438 luaS_resize(L, g->strt.size/2); /* table is too big */ 439 /* check size of buffer */ 440 if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ 441 size_t newsize = luaZ_sizebuffer(&g->buff) / 2; 442 luaZ_resizebuffer(L, &g->buff, newsize); 443 } 444} 445 446 447static void GCTM (lua_State *L) { 448 global_State *g = G(L); 449 GCObject *o = g->tmudata->gch.next; /* get first element */ 450 Udata *udata = rawgco2u(o); 451 const TValue *tm; 452 /* remove udata from `tmudata' */ 453 if (o == g->tmudata) /* last element? */ 454 g->tmudata = NULL; 455 else 456 g->tmudata->gch.next = udata->uv.next; 457 udata->uv.next = g->mainthread->next; /* return it to `root' list */ 458 g->mainthread->next = o; 459 makewhite(g, o); 460 tm = fasttm(L, udata->uv.metatable, TM_GC); 461 if (tm != NULL) { 462 lu_byte oldah = L->allowhook; 463 lu_mem oldt = g->GCthreshold; 464 L->allowhook = 0; /* stop debug hooks during GC tag method */ 465 g->GCthreshold = 2*g->totalbytes; /* avoid GC steps */ 466 setobj2s(L, L->top, tm); 467 setuvalue(L, L->top+1, udata); 468 L->top += 2; 469 luaD_call(L, L->top - 2, 0); 470 L->allowhook = oldah; /* restore hooks */ 471 g->GCthreshold = oldt; /* restore threshold */ 472 } 473} 474 475 476/* 477** Call all GC tag methods 478*/ 479void luaC_callGCTM (lua_State *L) { 480 while (G(L)->tmudata) 481 GCTM(L); 482} 483 484 485void luaC_freeall (lua_State *L) { 486 global_State *g = G(L); 487 int i; 488 g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT); /* mask to collect all elements */ 489 sweepwholelist(L, &g->rootgc); 490 for (i = 0; i < g->strt.size; i++) /* free all string lists */ 491 sweepwholelist(L, &g->strt.hash[i]); 492} 493 494 495static void markmt (global_State *g) { 496 int i; 497 for (i=0; i<NUM_TAGS; i++) 498 if (g->mt[i]) markobject(g, g->mt[i]); 499} 500 501 502/* mark root set */ 503static void markroot (lua_State *L) { 504 global_State *g = G(L); 505 g->gray = NULL; 506 g->grayagain = NULL; 507 g->weak = NULL; 508 markobject(g, g->mainthread); 509 /* make global table be traversed before main stack */ 510 markvalue(g, gt(g->mainthread)); 511 markvalue(g, registry(L)); 512 markmt(g); 513 g->gcstate = GCSpropagate; 514} 515 516 517static void remarkupvals (global_State *g) { 518 UpVal *uv; 519 for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { 520 lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); 521 if (isgray(obj2gco(uv))) 522 markvalue(g, uv->v); 523 } 524} 525 526 527static void atomic (lua_State *L) { 528 global_State *g = G(L); 529 size_t udsize; /* total size of userdata to be finalized */ 530 /* remark occasional upvalues of (maybe) dead threads */ 531 remarkupvals(g); 532 /* traverse objects cautch by write barrier and by 'remarkupvals' */ 533 propagateall(g); 534 /* remark weak tables */ 535 g->gray = g->weak; 536 g->weak = NULL; 537 lua_assert(!iswhite(obj2gco(g->mainthread))); 538 markobject(g, L); /* mark running thread */ 539 markmt(g); /* mark basic metatables (again) */ 540 propagateall(g); 541 /* remark gray again */ 542 g->gray = g->grayagain; 543 g->grayagain = NULL; 544 propagateall(g); 545 udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ 546 marktmu(g); /* mark `preserved' userdata */ 547 udsize += propagateall(g); /* remark, to propagate `preserveness' */ 548 cleartable(g->weak); /* remove collected objects from weak tables */ 549 /* flip current white */ 550 g->currentwhite = cast_byte(otherwhite(g)); 551 g->sweepstrgc = 0; 552 g->sweepgc = &g->rootgc; 553 g->gcstate = GCSsweepstring; 554 g->estimate = g->totalbytes - udsize; /* first estimate */ 555} 556 557 558static l_mem singlestep (lua_State *L) { 559 global_State *g = G(L); 560 /*lua_checkmemory(L);*/ 561 switch (g->gcstate) { 562 case GCSpause: { 563 markroot(L); /* start a new collection */ 564 return 0; 565 } 566 case GCSpropagate: { 567 if (g->gray) 568 return propagatemark(g); 569 else { /* no more `gray' objects */ 570 atomic(L); /* finish mark phase */ 571 return 0; 572 } 573 } 574 case GCSsweepstring: { 575 lu_mem old = g->totalbytes; 576 sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); 577 if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */ 578 g->gcstate = GCSsweep; /* end sweep-string phase */ 579 lua_assert(old >= g->totalbytes); 580 g->estimate -= old - g->totalbytes; 581 return GCSWEEPCOST; 582 } 583 case GCSsweep: { 584 lu_mem old = g->totalbytes; 585 g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); 586 if (*g->sweepgc == NULL) { /* nothing more to sweep? */ 587 checkSizes(L); 588 g->gcstate = GCSfinalize; /* end sweep phase */ 589 } 590 lua_assert(old >= g->totalbytes); 591 g->estimate -= old - g->totalbytes; 592 return GCSWEEPMAX*GCSWEEPCOST; 593 } 594 case GCSfinalize: { 595 if (g->tmudata) { 596 GCTM(L); 597 if (g->estimate > GCFINALIZECOST) 598 g->estimate -= GCFINALIZECOST; 599 return GCFINALIZECOST; 600 } 601 else { 602 g->gcstate = GCSpause; /* end collection */ 603 g->gcdept = 0; 604 return 0; 605 } 606 } 607 default: lua_assert(0); return 0; 608 } 609} 610 611 612void luaC_step (lua_State *L) { 613 global_State *g = G(L); 614 l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; 615 if (lim == 0) 616 lim = (MAX_LUMEM-1)/2; /* no limit */ 617 g->gcdept += g->totalbytes - g->GCthreshold; 618 do { 619 lim -= singlestep(L); 620 if (g->gcstate == GCSpause) 621 break; 622 } while (lim > 0); 623 if (g->gcstate != GCSpause) { 624 if (g->gcdept < GCSTEPSIZE) 625 g->GCthreshold = g->totalbytes + GCSTEPSIZE; /* - lim/g->gcstepmul;*/ 626 else { 627 g->gcdept -= GCSTEPSIZE; 628 g->GCthreshold = g->totalbytes; 629 } 630 } 631 else { 632 lua_assert(g->totalbytes >= g->estimate); 633 setthreshold(g); 634 } 635} 636 637 638void luaC_fullgc (lua_State *L) { 639 global_State *g = G(L); 640 if (g->gcstate <= GCSpropagate) { 641 /* reset sweep marks to sweep all elements (returning them to white) */ 642 g->sweepstrgc = 0; 643 g->sweepgc = &g->rootgc; 644 /* reset other collector lists */ 645 g->gray = NULL; 646 g->grayagain = NULL; 647 g->weak = NULL; 648 g->gcstate = GCSsweepstring; 649 } 650 lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate); 651 /* finish any pending sweep phase */ 652 while (g->gcstate != GCSfinalize) { 653 lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep); 654 singlestep(L); 655 } 656 markroot(L); 657 while (g->gcstate != GCSpause) { 658 singlestep(L); 659 } 660 setthreshold(g); 661} 662 663 664void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { 665 global_State *g = G(L); 666 lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); 667 lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); 668 lua_assert(ttype(&o->gch) != LUA_TTABLE); 669 /* must keep invariant? */ 670 if (g->gcstate == GCSpropagate) 671 reallymarkobject(g, v); /* restore invariant */ 672 else /* don't mind */ 673 makewhite(g, o); /* mark as white just to avoid other barriers */ 674} 675 676 677void luaC_barrierback (lua_State *L, Table *t) { 678 global_State *g = G(L); 679 GCObject *o = obj2gco(t); 680 lua_assert(isblack(o) && !isdead(g, o)); 681 lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); 682 black2gray(o); /* make table gray (again) */ 683 t->gclist = g->grayagain; 684 g->grayagain = o; 685} 686 687 688void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { 689 global_State *g = G(L); 690 o->gch.next = g->rootgc; 691 g->rootgc = o; 692 o->gch.marked = luaC_white(g); 693 o->gch.tt = tt; 694} 695 696 697void luaC_linkupval (lua_State *L, UpVal *uv) { 698 global_State *g = G(L); 699 GCObject *o = obj2gco(uv); 700 o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ 701 g->rootgc = o; 702 if (isgray(o)) { 703 if (g->gcstate == GCSpropagate) { 704 gray2black(o); /* closed upvalues need barrier */ 705 luaC_barrier(L, uv, uv->v); 706 } 707 else { /* sweep phase: sweep it (turning it into white) */ 708 makewhite(g, o); 709 lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); 710 } 711 } 712} 713 714