aboutsummaryrefslogtreecommitdiff
path: root/lgc.c
diff options
context:
space:
mode:
Diffstat (limited to 'lgc.c')
-rw-r--r--lgc.c357
1 files changed, 203 insertions, 154 deletions
diff --git a/lgc.c b/lgc.c
index dbac2f1a..f38f08f9 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.c,v 2.43 2008/02/11 15:46:03 roberto Exp roberto $ 2** $Id: lgc.c,v 2.44 2008/02/19 18:55:09 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*/
@@ -53,6 +53,15 @@
53#define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause) 53#define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause)
54 54
55 55
56static void reallymarkobject (global_State *g, GCObject *o);
57
58
59/*
60** {======================================================
61** Generic functions
62** =======================================================
63*/
64
56static void linktable (Table *h, GCObject **p) { 65static void linktable (Table *h, GCObject **p) {
57 h->gclist = *p; 66 h->gclist = *p;
58 *p = obj2gco(h); 67 *p = obj2gco(h);
@@ -83,6 +92,65 @@ static int iscleared (const TValue *o, int iskey) {
83 (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); 92 (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o))));
84} 93}
85 94
95void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
96 global_State *g = G(L);
97 lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
98 lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
99 lua_assert(ttype(gch(o)) != LUA_TTABLE);
100 /* must keep invariant? */
101 if (g->gcstate == GCSpropagate)
102 reallymarkobject(g, v); /* restore invariant */
103 else /* don't mind */
104 makewhite(g, o); /* mark as white just to avoid other barriers */
105}
106
107
108void luaC_barrierback (lua_State *L, Table *t) {
109 global_State *g = G(L);
110 GCObject *o = obj2gco(t);
111 lua_assert(isblack(o) && !isdead(g, o));
112 lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
113 black2gray(o); /* make table gray (again) */
114 t->gclist = g->grayagain;
115 g->grayagain = o;
116}
117
118
119void luaC_link (lua_State *L, GCObject *o, lu_byte tt) {
120 global_State *g = G(L);
121 gch(o)->marked = luaC_white(g);
122 gch(o)->tt = tt;
123 gch(o)->next = g->rootgc;
124 g->rootgc = o;
125}
126
127
128void luaC_linkupval (lua_State *L, UpVal *uv) {
129 global_State *g = G(L);
130 GCObject *o = obj2gco(uv);
131 gch(o)->next = g->rootgc; /* link upvalue into `rootgc' list */
132 g->rootgc = o;
133 if (isgray(o)) {
134 if (g->gcstate == GCSpropagate) {
135 gray2black(o); /* closed upvalues need barrier */
136 luaC_barrier(L, uv, uv->v);
137 }
138 else { /* sweep phase: sweep it (turning it into white) */
139 makewhite(g, o);
140 lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
141 }
142 }
143}
144
145/* }====================================================== */
146
147
148
149/*
150** {======================================================
151** Mark functions
152** =======================================================
153*/
86 154
87static void reallymarkobject (global_State *g, GCObject *o) { 155static void reallymarkobject (global_State *g, GCObject *o) {
88 lua_assert(iswhite(o) && !isdead(g, o)); 156 lua_assert(iswhite(o) && !isdead(g, o));
@@ -129,36 +197,60 @@ static void reallymarkobject (global_State *g, GCObject *o) {
129} 197}
130 198
131 199
132/* move 'dead' udata that need finalization to list 'tobefnz' */ 200static void markmt (global_State *g) {
133size_t luaC_separateudata (lua_State *L, int all) { 201 int i;
202 for (i=0; i<NUM_TAGS; i++)
203 markobject(g, g->mt[i]);
204}
205
206
207static void markbeingfnz (global_State *g) {
208 GCObject *u = g->tobefnz;
209 if (u) {
210 do {
211 u = gch(u)->next;
212 lua_assert(testbit(gch(u)->marked, SEPARATED));
213 lua_assert(!iswhite(u)); /* must be marked, if left from previous GC */
214 makewhite(g, u);
215 reallymarkobject(g, u);
216 } while (u != g->tobefnz);
217 }
218}
219
220
221/* mark root set */
222static void markroot (lua_State *L) {
134 global_State *g = G(L); 223 global_State *g = G(L);
135 size_t deadmem = 0; 224 g->gray = NULL;
136 GCObject **p = &g->tmudata; 225 g->grayagain = NULL;
137 GCObject *curr; 226 g->weak = g->ephemeron = g->allweak = NULL;
138 while ((curr = *p) != NULL) { 227 markobject(g, g->mainthread);
139 lua_assert(ttisuserdata(gch(curr)) && !isfinalized(gco2u(curr))); 228 /* make global table be traversed before main stack */
140 lua_assert(testbit(gch(curr)->marked, SEPARATED)); 229 markvalue(g, gt(g->mainthread));
141 if (all) makewhite(g, curr); /* if 'all', collect all objects */ 230 markvalue(g, registry(L));
142 if (!iswhite(curr)) /* not being collected? */ 231 markmt(g);
143 p = &gch(curr)->next; /* don't bother with it */ 232 markbeingfnz(g); /* mark any finalizing userdata left from previous cycle */
144 else { 233 g->gcstate = GCSpropagate;
145 l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ 234}
146 reallymarkobject(g, curr); /* won't be collected now */ 235
147 deadmem += sizeudata(gco2u(curr)); 236
148 *p = gch(curr)->next; /* remove 'curr' from 'tmudata' list */ 237static void remarkupvals (global_State *g) {
149 /* link 'curr' at the end of 'tobefnz' list */ 238 UpVal *uv;
150 if (g->tobefnz == NULL) /* list is empty? */ 239 for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) {
151 g->tobefnz = gch(curr)->next = curr; /* creates a circular list */ 240 lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
152 else { 241 if (isgray(obj2gco(uv)))
153 gch(curr)->next = gch(g->tobefnz)->next; 242 markvalue(g, uv->v);
154 gch(g->tobefnz)->next = curr;
155 g->tobefnz = curr;
156 }
157 }
158 } 243 }
159 return deadmem;
160} 244}
161 245
246/* }====================================================== */
247
248
249/*
250** {======================================================
251** Traverse functions
252** =======================================================
253*/
162 254
163static void traverseweakvalue (global_State *g, Table *h) { 255static void traverseweakvalue (global_State *g, Table *h) {
164 int i = sizenode(h); 256 int i = sizenode(h);
@@ -382,6 +474,14 @@ static size_t propagateall (global_State *g) {
382} 474}
383 475
384 476
477static void traverselistofgrays (global_State *g, GCObject **l) {
478 lua_assert(g->gray == NULL); /* no grays left */
479 g->gray = *l; /* now 'l' is new gray list */
480 *l = NULL;
481 propagateall(g);
482}
483
484
385static void convergeephemerons (global_State *g) { 485static void convergeephemerons (global_State *g) {
386 int changed; 486 int changed;
387 do { 487 do {
@@ -399,11 +499,16 @@ static void convergeephemerons (global_State *g) {
399 } while (changed); 499 } while (changed);
400} 500}
401 501
502/* }====================================================== */
402 503
403 504
404/* 505/*
405** clear collected entries from weaktables 506** {======================================================
507** Sweep Functions
508** =======================================================
406*/ 509*/
510
511/* clear collected entries from weaktables */
407static void cleartable (GCObject *l) { 512static void cleartable (GCObject *l) {
408 while (l) { 513 while (l) {
409 Table *h = gco2t(l); 514 Table *h = gco2t(l);
@@ -445,7 +550,6 @@ static void freeobj (lua_State *L, GCObject *o) {
445} 550}
446 551
447 552
448
449#define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) 553#define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM)
450 554
451 555
@@ -471,6 +575,8 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
471} 575}
472 576
473 577
578/* sweep list where all objects are alive (dead udata were removed
579 when separated from this list) */
474static GCObject **unmarklist (global_State *g, GCObject **p, lu_mem count) { 580static GCObject **unmarklist (global_State *g, GCObject **p, lu_mem count) {
475 for (; *p != NULL && count-- > 0; p = &gch(*p)->next) { 581 for (; *p != NULL && count-- > 0; p = &gch(*p)->next) {
476 lua_assert(ttisuserdata(gch(*p)) && !isdead(g, *p)); 582 lua_assert(ttisuserdata(gch(*p)) && !isdead(g, *p));
@@ -479,6 +585,14 @@ static GCObject **unmarklist (global_State *g, GCObject **p, lu_mem count) {
479 return p; 585 return p;
480} 586}
481 587
588/* }====================================================== */
589
590
591/*
592** {======================================================
593** Finalization
594** =======================================================
595*/
482 596
483static void checkSizes (lua_State *L) { 597static void checkSizes (lua_State *L) {
484 global_State *g = G(L); 598 global_State *g = G(L);
@@ -541,6 +655,63 @@ void luaC_callGCTM (lua_State *L) {
541} 655}
542 656
543 657
658/* move 'dead' udata that need finalization to list 'tobefnz' */
659size_t luaC_separateudata (lua_State *L, int all) {
660 global_State *g = G(L);
661 size_t deadmem = 0;
662 GCObject **p = &g->tmudata;
663 GCObject *curr;
664 while ((curr = *p) != NULL) {
665 lua_assert(ttisuserdata(gch(curr)) && !isfinalized(gco2u(curr)));
666 lua_assert(testbit(gch(curr)->marked, SEPARATED));
667 if (all) makewhite(g, curr); /* if 'all', collect all objects */
668 if (!iswhite(curr)) /* not being collected? */
669 p = &gch(curr)->next; /* don't bother with it */
670 else {
671 l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */
672 reallymarkobject(g, curr); /* won't be collected now */
673 deadmem += sizeudata(gco2u(curr));
674 *p = gch(curr)->next; /* remove 'curr' from 'tmudata' list */
675 /* link 'curr' at the end of 'tobefnz' list */
676 if (g->tobefnz == NULL) /* list is empty? */
677 g->tobefnz = gch(curr)->next = curr; /* creates a circular list */
678 else {
679 gch(curr)->next = gch(g->tobefnz)->next;
680 gch(g->tobefnz)->next = curr;
681 g->tobefnz = curr;
682 }
683 }
684 }
685 return deadmem;
686}
687
688
689void luaC_checkfinalizer (lua_State *L, Udata *u) {
690 global_State *g = G(L);
691 if (testbit(u->uv.marked, SEPARATED) || /* userdata is already separated... */
692 isfinalized(&u->uv) || /* ... or is finalized... */
693 gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */
694 return; /* nothing to be done */
695 else { /* move 'u' from root list to 'tmudata' list */
696 GCObject **p;
697 for (p = &g->rootgc; *p != obj2gco(u); p = &gch(*p)->next)
698 lua_assert(*p != NULL); /* 'u' must be in this list */
699 *p = u->uv.next; /* remove 'u' from root list */
700 u->uv.next = g->tmudata; /* link it in 'tmudata' list */
701 g->tmudata = obj2gco(u);
702 l_setbit(u->uv.marked, SEPARATED); /* mark it as such */
703 }
704}
705
706/* }====================================================== */
707
708
709/*
710** {======================================================
711** GC control
712** =======================================================
713*/
714
544void luaC_freeall (lua_State *L) { 715void luaC_freeall (lua_State *L) {
545 global_State *g = G(L); 716 global_State *g = G(L);
546 int i; 717 int i;
@@ -557,61 +728,6 @@ void luaC_freeall (lua_State *L) {
557} 728}
558 729
559 730
560static void markmt (global_State *g) {
561 int i;
562 for (i=0; i<NUM_TAGS; i++)
563 markobject(g, g->mt[i]);
564}
565
566
567static void markbeingfnz (global_State *g) {
568 GCObject *u = g->tobefnz;
569 if (u) {
570 do {
571 u = gch(u)->next;
572 lua_assert(testbit(gch(u)->marked, SEPARATED));
573 lua_assert(!iswhite(u)); /* must be marked, if left from previous GC */
574 makewhite(g, u);
575 reallymarkobject(g, u);
576 } while (u != g->tobefnz);
577 }
578}
579
580
581/* mark root set */
582static void markroot (lua_State *L) {
583 global_State *g = G(L);
584 g->gray = NULL;
585 g->grayagain = NULL;
586 g->weak = g->ephemeron = g->allweak = NULL;
587 markobject(g, g->mainthread);
588 /* make global table be traversed before main stack */
589 markvalue(g, gt(g->mainthread));
590 markvalue(g, registry(L));
591 markmt(g);
592 markbeingfnz(g); /* mark any finalizing userdata left from previous cycle */
593 g->gcstate = GCSpropagate;
594}
595
596
597static void remarkupvals (global_State *g) {
598 UpVal *uv;
599 for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) {
600 lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
601 if (isgray(obj2gco(uv)))
602 markvalue(g, uv->v);
603 }
604}
605
606
607static void marklistofgrays (global_State *g, GCObject **l) {
608 lua_assert(g->gray == NULL); /* no grays left */
609 g->gray = *l; /* now 'l' is new gray list */
610 *l = NULL;
611 propagateall(g);
612}
613
614
615static void atomic (lua_State *L) { 731static void atomic (lua_State *L) {
616 global_State *g = G(L); 732 global_State *g = G(L);
617 size_t udsize; /* total size of userdata to be finalized */ 733 size_t udsize; /* total size of userdata to be finalized */
@@ -626,8 +742,8 @@ static void atomic (lua_State *L) {
626 markobject(g, L); /* mark running thread */ 742 markobject(g, L); /* mark running thread */
627 markmt(g); /* mark basic metatables (again) */ 743 markmt(g); /* mark basic metatables (again) */
628 propagateall(g); 744 propagateall(g);
629 marklistofgrays(g, &g->ephemeron); /* remark ephemeron tables */ 745 traverselistofgrays(g, &g->ephemeron); /* remark ephemeron tables */
630 marklistofgrays(g, &g->grayagain); /* remark gray again */ 746 traverselistofgrays(g, &g->grayagain); /* remark gray again */
631 convergeephemerons(g); 747 convergeephemerons(g);
632 udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ 748 udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */
633 udsize += propagateall(g); /* remark, to propagate `preserveness' */ 749 udsize += propagateall(g); /* remark, to propagate `preserveness' */
@@ -762,73 +878,6 @@ void luaC_fullgc (lua_State *L, int isemergency) {
762 setthreshold(g); 878 setthreshold(g);
763} 879}
764 880
765 881/* }====================================================== */
766void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
767 global_State *g = G(L);
768 lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
769 lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
770 lua_assert(ttype(gch(o)) != LUA_TTABLE);
771 /* must keep invariant? */
772 if (g->gcstate == GCSpropagate)
773 reallymarkobject(g, v); /* restore invariant */
774 else /* don't mind */
775 makewhite(g, o); /* mark as white just to avoid other barriers */
776}
777
778
779void luaC_barrierback (lua_State *L, Table *t) {
780 global_State *g = G(L);
781 GCObject *o = obj2gco(t);
782 lua_assert(isblack(o) && !isdead(g, o));
783 lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
784 black2gray(o); /* make table gray (again) */
785 t->gclist = g->grayagain;
786 g->grayagain = o;
787}
788
789
790void luaC_link (lua_State *L, GCObject *o, lu_byte tt) {
791 global_State *g = G(L);
792 gch(o)->marked = luaC_white(g);
793 gch(o)->tt = tt;
794 gch(o)->next = g->rootgc;
795 g->rootgc = o;
796}
797
798
799void luaC_linkupval (lua_State *L, UpVal *uv) {
800 global_State *g = G(L);
801 GCObject *o = obj2gco(uv);
802 gch(o)->next = g->rootgc; /* link upvalue into `rootgc' list */
803 g->rootgc = o;
804 if (isgray(o)) {
805 if (g->gcstate == GCSpropagate) {
806 gray2black(o); /* closed upvalues need barrier */
807 luaC_barrier(L, uv, uv->v);
808 }
809 else { /* sweep phase: sweep it (turning it into white) */
810 makewhite(g, o);
811 lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
812 }
813 }
814}
815
816
817void luaC_checkfinalizer (lua_State *L, Udata *u) {
818 global_State *g = G(L);
819 if (testbit(u->uv.marked, SEPARATED) || /* userdata is already separated... */
820 isfinalized(&u->uv) || /* ... or is finalized... */
821 gfasttm(g, u->uv.metatable, TM_GC) == NULL) /* or has no finalization? */
822 return; /* nothing to be done */
823 else { /* move 'u' from root list to tobefnz list */
824 GCObject **p;
825 for (p = &g->rootgc; *p != obj2gco(u); p = &gch(*p)->next)
826 lua_assert(*p != NULL); /* 'u' must be in this list */
827 *p = u->uv.next; /* remove 'u' from root list */
828 u->uv.next = g->tmudata; /* link it in tobefnz list */
829 g->tmudata = obj2gco(u);
830 l_setbit(u->uv.marked, SEPARATED); /* mark it as such */
831 }
832}
833 882
834 883