aboutsummaryrefslogtreecommitdiff
path: root/lgc.c
diff options
context:
space:
mode:
Diffstat (limited to 'lgc.c')
-rw-r--r--lgc.c257
1 files changed, 129 insertions, 128 deletions
diff --git a/lgc.c b/lgc.c
index 86f4e637..561c6350 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.c,v 2.7 2004/04/30 20:13:38 roberto Exp roberto $ 2** $Id: lgc.c,v 2.8 2004/08/10 19:17:23 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*/
@@ -25,10 +25,11 @@
25 25
26#define GCSTEPSIZE (40*sizeof(TValue)) 26#define GCSTEPSIZE (40*sizeof(TValue))
27#define STEPMUL 2 27#define STEPMUL 2
28#define GCFREECOST (sizeof(TValue)/10) 28#define GCSWEEPMAX 40
29#define GCSWEEPCOST (sizeof(TValue)/20) 29#define GCSWEEPCOST 1
30#define GCFINALIZECOST (10*sizeof(TValue)) 30#define GCFINALIZECOST (10*sizeof(TValue))
31#define WAITNEXTCYCLE (10 * GCSTEPSIZE) 31#define WAITNEXTCYCLE (40 * GCSTEPSIZE)
32#define WAITNEXTCYCLEGN (200 * GCSTEPSIZE)
32 33
33 34
34#define FIXEDMASK bitmask(FIXEDBIT) 35#define FIXEDMASK bitmask(FIXEDBIT)
@@ -269,60 +270,61 @@ static void traversestack (global_State *g, lua_State *l) {
269 270
270 271
271/* 272/*
272** traverse a given `quantity' of gray objects, 273** traverse one gray object, turning it to black.
273** turning them to black. Returns extra `quantity' traversed. 274** Returns `quantity' traversed.
274*/ 275*/
275static l_mem propagatemarks (global_State *g, l_mem lim) { 276static l_mem propagatemark (global_State *g) {
276 GCObject *o; 277 GCObject *o = g->gray;
277 while ((o = g->gray) != NULL) { 278 lua_assert(isgray(o));
278 lua_assert(isgray(o)); 279 gray2black(o);
279 gray2black(o); 280 switch (o->gch.tt) {
280 switch (o->gch.tt) { 281 case LUA_TTABLE: {
281 case LUA_TTABLE: { 282 Table *h = gco2h(o);
282 Table *h = gco2h(o); 283 g->gray = h->gclist;
283 g->gray = h->gclist; 284 if (traversetable(g, h)) /* table is weak? */
284 if (traversetable(g, h)) /* table is weak? */ 285 black2gray(o); /* keep it gray */
285 black2gray(o); /* keep it gray */ 286 return sizeof(Table) + sizeof(TValue) * h->sizearray +
286 lim -= sizeof(Table) + sizeof(TValue) * h->sizearray + 287 sizeof(Node) * sizenode(h);
287 sizeof(Node) * sizenode(h); 288 break;
288 break; 289 }
289 } 290 case LUA_TFUNCTION: {
290 case LUA_TFUNCTION: { 291 Closure *cl = gco2cl(o);
291 Closure *cl = gco2cl(o); 292 g->gray = cl->c.gclist;
292 g->gray = cl->c.gclist; 293 traverseclosure(g, cl);
293 traverseclosure(g, cl); 294 return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) :
294 lim -= (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : 295 sizeLclosure(cl->l.nupvalues);
295 sizeLclosure(cl->l.nupvalues); 296 break;
296 break;
297 }
298 case LUA_TTHREAD: {
299 lua_State *th = gco2th(o);
300 g->gray = th->gclist;
301 th->gclist = g->grayagain;
302 g->grayagain = o;
303 black2gray(o);
304 traversestack(g, th);
305 lim -= sizeof(lua_State) + sizeof(TValue) * th->stacksize +
306 sizeof(CallInfo) * th->size_ci;
307 break;
308 }
309 case LUA_TPROTO: {
310 Proto *p = gco2p(o);
311 g->gray = p->gclist;
312 traverseproto(g, p);
313 lim -= 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 break;
320 }
321 default: lua_assert(0);
322 } 297 }
323 if (lim <= 0) return lim; 298 case LUA_TTHREAD: {
299 lua_State *th = gco2th(o);
300 g->gray = th->gclist;
301 th->gclist = g->grayagain;
302 g->grayagain = o;
303 black2gray(o);
304 traversestack(g, th);
305 return sizeof(lua_State) + sizeof(TValue) * th->stacksize +
306 sizeof(CallInfo) * th->size_ci;
307 break;
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 break;
320 }
321 default: lua_assert(0); return 0;
324 } 322 }
325 return lim; 323}
324
325
326static void propagateall (global_State *g) {
327 while (g->gray) propagatemark(g);
326} 328}
327 329
328 330
@@ -384,6 +386,7 @@ static void freeobj (lua_State *L, GCObject *o) {
384 break; 386 break;
385 } 387 }
386 case LUA_TSTRING: { 388 case LUA_TSTRING: {
389 G(L)->strt.nuse--;
387 luaM_free(L, o, sizestring(gco2ts(o)->len)); 390 luaM_free(L, o, sizestring(gco2ts(o)->len));
388 break; 391 break;
389 } 392 }
@@ -396,59 +399,50 @@ static void freeobj (lua_State *L, GCObject *o) {
396} 399}
397 400
398 401
399static l_mem sweepwholelist (lua_State *L, GCObject **p, int keepfixed, 402
400 lu_int32 *count); 403#define sweepwholelist(L,p) sweeplist(L,p,LUA_MAXINT32)
401 404
402 405
403static GCObject **sweeplist (lua_State *L, GCObject **p, int keepfixed, 406static GCObject **sweeplist (lua_State *L, GCObject **p, lu_int32 count) {
404 l_mem *plim, lu_int32 *count) {
405 GCObject *curr; 407 GCObject *curr;
406 global_State *g = G(L); 408 global_State *g = G(L);
407 l_mem lim = *plim; 409 int whitebit = otherwhite(g);
408 int deadmask = otherwhite(g); 410 int deadmask = whitebit | FIXEDMASK;
409 if (keepfixed) deadmask |= FIXEDMASK;
410 while ((curr = *p) != NULL) { 411 while ((curr = *p) != NULL) {
411 if (((curr->gch.marked ^ FIXEDMASK) & deadmask) != deadmask) { 412 if ((curr->gch.marked ^ whitebit) & deadmask) {
412 makewhite(g, curr); 413 lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT));
414 if (!G(L)->gcgenerational || isdead(g, curr))
415 makewhite(g, curr);
413 if (curr->gch.tt == LUA_TTHREAD) 416 if (curr->gch.tt == LUA_TTHREAD)
414 lim -= sweepwholelist(L, &gco2th(curr)->openupval, keepfixed, count); 417 sweepwholelist(L, &gco2th(curr)->openupval);
415 p = &curr->gch.next; 418 p = &curr->gch.next;
416 lim -= GCSWEEPCOST;
417 } 419 }
418 else { 420 else {
419 lua_assert(iswhite(curr)); 421 lua_assert(isdead(g, curr));
420 *p = curr->gch.next; 422 *p = curr->gch.next;
421 if (curr == g->rootgc) /* is the first element of the list? */ 423 if (curr == g->rootgc) /* is the first element of the list? */
422 g->rootgc = curr->gch.next; /* adjust first */ 424 g->rootgc = curr->gch.next; /* adjust first */
423 freeobj(L, curr); 425 freeobj(L, curr);
424 lim -= GCFREECOST;
425 if (count) (*count)--;
426 } 426 }
427 if (lim <= 0) break; 427 if (count-- == 0) break;
428 } 428 }
429 *plim = lim;
430 return p; 429 return p;
431} 430}
432 431
433 432
434static l_mem sweepwholelist (lua_State *L, GCObject **p, int keepfixed, 433static void sweepstrings (lua_State *L) {
435 lu_int32 *count) { 434 global_State *g = G(L);
436 l_mem lim = MAXLMEM; 435 sweepwholelist(L, &G(L)->strt.hash[g->sweepstrgc++]);
437 /* empty lists are quite common here, so avoid useless calls */
438 if (*p) sweeplist(L, p, keepfixed, &lim, count);
439 return MAXLMEM - lim;
440} 436}
441 437
442 438
443static l_mem sweepstrings (lua_State *L, int keepfixed, l_mem lim) { 439static void freelist (lua_State *L, GCObject **p) {
444 int i; 440 while (*p) {
445 global_State *g = G(L); 441 GCObject *curr = *p;
446 for (i = g->sweepstrgc; i < g->strt.size; i++) { /* for each list */ 442 *p = (*p)->gch.next;
447 lim -= sweepwholelist(L, &G(L)->strt.hash[i], keepfixed, &g->strt.nuse); 443 if (curr != obj2gco(L))
448 if (lim <= 0) break; 444 freeobj(L, curr);
449 } 445 }
450 g->sweepstrgc = i+1;
451 return lim;
452} 446}
453 447
454 448
@@ -497,19 +491,12 @@ void luaC_callGCTM (lua_State *L) {
497} 491}
498 492
499 493
500void luaC_sweepall (lua_State *L) { 494void luaC_freeall (lua_State *L) {
501 global_State *g = G(L); 495 global_State *g = G(L);
502 l_mem dummy = MAXLMEM; 496 int i;
503 /* finish (occasional) current sweep */ 497 freelist(L, &g->rootgc);
504 sweepstrings(L, 0, MAXLMEM); 498 for (i = 0; i < g->strt.size; i++) /* free all string lists */
505 sweeplist(L, &g->rootgc, 0, &dummy, NULL); 499 freelist(L, &G(L)->strt.hash[i]);
506 /* do a whole new sweep */
507 markobject(g, g->mainthread); /* cannot collect main thread */
508 g->currentwhite = otherwhite(g);
509 g->sweepgc = &g->rootgc;
510 g->sweepstrgc = 0;
511 sweepstrings(L, 0, MAXLMEM);
512 sweeplist(L, &g->rootgc, 0, &dummy, NULL);
513} 500}
514 501
515 502
@@ -553,64 +540,68 @@ static void atomic (lua_State *L) {
553 g->weak = NULL; 540 g->weak = NULL;
554 lua_assert(!iswhite(obj2gco(g->mainthread))); 541 lua_assert(!iswhite(obj2gco(g->mainthread)));
555 markobject(g, L); /* mark running thread */ 542 markobject(g, L); /* mark running thread */
556 propagatemarks(g, MAXLMEM); 543 propagateall(g);
557 /* remark gray again */ 544 /* remark gray again */
558 g->gray = g->grayagain; 545 g->gray = g->grayagain;
559 g->grayagain = NULL; 546 g->grayagain = NULL;
560 propagatemarks(g, MAXLMEM); 547 propagateall(g);
561 luaC_separateudata(L, 0); /* separate userdata to be preserved */ 548 luaC_separateudata(L, 0); /* separate userdata to be preserved */
562 marktmu(g); /* mark `preserved' userdata */ 549 marktmu(g); /* mark `preserved' userdata */
563 propagatemarks(g, MAXLMEM); /* remark, to propagate `preserveness' */ 550 propagateall(g); /* remark, to propagate `preserveness' */
564 cleartable(g->weak); /* remove collected objects from weak tables */ 551 cleartable(g->weak); /* remove collected objects from weak tables */
565 /* flip current white */ 552 /* flip current white */
566 g->currentwhite = otherwhite(g); 553 g->currentwhite = otherwhite(g);
554 g->sweepstrgc = 0;
555 g->sweepgc = &g->rootgc;
567 g->gcstate = GCSsweepstring; 556 g->gcstate = GCSsweepstring;
557 if (g->gcgenerational++ > 20) g->gcgenerational = 0;
568} 558}
569 559
570 560
571static l_mem singlestep (lua_State *L, l_mem lim) { 561static l_mem singlestep (lua_State *L) {
572 global_State *g = G(L); 562 global_State *g = G(L);
563 /*lua_checkmemory(L);*/
573 switch (g->gcstate) { 564 switch (g->gcstate) {
574 case GCSpropagate: { 565 case GCSpropagate: {
575 if (g->gray) 566 if (g->gray)
576 lim = propagatemarks(g, lim); 567 return propagatemark(g);
577 else { /* no more `gray' objects */ 568 else { /* no more `gray' objects */
578 atomic(L); /* finish mark phase */ 569 atomic(L); /* finish mark phase */
579 lim = 0; 570 return 0;
580 } 571 }
581 break;
582 } 572 }
583 case GCSsweepstring: { 573 case GCSsweepstring: {
584 lim = sweepstrings(L, 1, lim); 574 sweepstrings(L);
585 if (g->sweepstrgc >= g->strt.size) { /* nothing more to sweep? */ 575 if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */
586 g->sweepstrgc = 0;
587 g->gcstate = GCSsweep; /* end sweep-string phase */ 576 g->gcstate = GCSsweep; /* end sweep-string phase */
588 } 577 return GCSWEEPCOST;
589 break;
590 } 578 }
591 case GCSsweep: { 579 case GCSsweep: {
592 g->sweepgc = sweeplist(L, g->sweepgc, 1, &lim, NULL); 580 g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
593 if (*g->sweepgc == NULL) { /* nothing more to sweep? */ 581 if (*g->sweepgc == NULL) { /* nothing more to sweep? */
594 checkSizes(L); 582 checkSizes(L);
595 g->sweepgc = &g->rootgc;
596 g->gcstate = GCSfinalize; /* end sweep phase */ 583 g->gcstate = GCSfinalize; /* end sweep phase */
597 } 584 }
598 break; 585 return GCSWEEPCOST;
599 } 586 }
600 case GCSfinalize: { 587 case GCSfinalize: {
601 if (g->tmudata) { 588 if (g->tmudata) {
602 GCTM(L); 589 GCTM(L);
603 lim -= GCFINALIZECOST; 590 return GCFINALIZECOST;
604 } 591 }
605 else { /* no more `udata' to finalize */ 592 else { /* no more `udata' to finalize */
606 markroot(L); /* may restart collection */ 593 if (g->gcgenerational) {
607 lim = 0; 594 atomic(L);
595 return WAITNEXTCYCLEGN;
596 }
597 else {
598 markroot(L); /* may restart collection */
599 return WAITNEXTCYCLE;
600 }
608 } 601 }
609 break;
610 } 602 }
611 default: lua_assert(0); 603 default: lua_assert(0); return 0;
612 } 604 }
613 return lim;
614} 605}
615 606
616 607
@@ -618,11 +609,7 @@ void luaC_step (lua_State *L) {
618 global_State *g = G(L); 609 global_State *g = G(L);
619 l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * STEPMUL; 610 l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * STEPMUL;
620 do { 611 do {
621 lim = singlestep(L, lim); 612 lim -= singlestep(L);
622 if (g->gcstate == GCSfinalize && g->tmudata == NULL) {
623 lim = -WAITNEXTCYCLE;
624 break; /* do not start new collection */
625 }
626 } while (lim > 0); 613 } while (lim > 0);
627 g->GCthreshold = g->nblocks + GCSTEPSIZE - lim/STEPMUL; 614 g->GCthreshold = g->nblocks + GCSTEPSIZE - lim/STEPMUL;
628 lua_assert((long)g->nblocks + (long)GCSTEPSIZE >= lim/STEPMUL); 615 lua_assert((long)g->nblocks + (long)GCSTEPSIZE >= lim/STEPMUL);
@@ -631,12 +618,26 @@ void luaC_step (lua_State *L) {
631 618
632void luaC_fullgc (lua_State *L) { 619void luaC_fullgc (lua_State *L) {
633 global_State *g = G(L); 620 global_State *g = G(L);
621 if (g->gcstate == GCSpropagate || g->gcgenerational) {
622 g->gcgenerational = 0;
623 /* reset sweep marks to sweep all elements (returning them to white) */
624 g->sweepstrgc = 0;
625 g->sweepgc = &g->rootgc;
626 /* reset other collector lists */
627 g->gray = NULL;
628 g->grayagain = NULL;
629 g->weak = NULL;
630 g->gcstate = GCSsweepstring;
631 }
632 /* finish any pending sweep phase */
634 while (g->gcstate != GCSfinalize) { 633 while (g->gcstate != GCSfinalize) {
635 singlestep(L, MAXLMEM); 634 singlestep(L);
636 } 635 }
637 markroot(L); 636 markroot(L);
637 lua_assert(!g->gcgenerational);
638 while (g->gcstate != GCSfinalize) { 638 while (g->gcstate != GCSfinalize) {
639 singlestep(L, MAXLMEM); 639 singlestep(L);
640 g->gcgenerational = 0; /* keep it in this mode */
640 } 641 }
641 g->GCthreshold = g->nblocks + GCSTEPSIZE; 642 g->GCthreshold = g->nblocks + GCSTEPSIZE;
642 luaC_callGCTM(L); /* call finalizers */ 643 luaC_callGCTM(L); /* call finalizers */
@@ -646,7 +647,7 @@ void luaC_fullgc (lua_State *L) {
646void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { 647void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
647 global_State *g = G(L); 648 global_State *g = G(L);
648 lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); 649 lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
649 lua_assert(g->gcstate != GCSfinalize); 650 lua_assert(g->gcgenerational || g->gcstate != GCSfinalize);
650 if (g->gcstate != GCSpropagate) /* sweeping phases? */ 651 if (g->gcstate != GCSpropagate) /* sweeping phases? */
651 black2gray(o); /* just mark as gray to avoid other barriers */ 652 black2gray(o); /* just mark as gray to avoid other barriers */
652 else /* breaking invariant! */ 653 else /* breaking invariant! */
@@ -657,7 +658,7 @@ void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
657void luaC_barrierback (lua_State *L, GCObject *o, GCObject *v) { 658void luaC_barrierback (lua_State *L, GCObject *o, GCObject *v) {
658 global_State *g = G(L); 659 global_State *g = G(L);
659 lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); 660 lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
660 lua_assert(g->gcstate != GCSfinalize); 661 lua_assert(g->gcgenerational || g->gcstate != GCSfinalize);
661 black2gray(o); /* make table gray (again) */ 662 black2gray(o); /* make table gray (again) */
662 gco2h(o)->gclist = g->grayagain; 663 gco2h(o)->gclist = g->grayagain;
663 g->grayagain = o; 664 g->grayagain = o;
@@ -679,7 +680,7 @@ void luaC_linkupval (lua_State *L, UpVal *uv) {
679 o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ 680 o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */
680 g->rootgc = o; 681 g->rootgc = o;
681 if (isgray(o)) { 682 if (isgray(o)) {
682 if (g->gcstate == GCSpropagate) { 683 if (g->gcstate == GCSpropagate || g->gcgenerational) {
683 gray2black(o); /* closed upvalues need barrier */ 684 gray2black(o); /* closed upvalues need barrier */
684 luaC_barrier(L, uv, uv->v); 685 luaC_barrier(L, uv, uv->v);
685 } 686 }