aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lfunc.c2
-rw-r--r--lgc.c54
-rw-r--r--lgc.h23
3 files changed, 40 insertions, 39 deletions
diff --git a/lfunc.c b/lfunc.c
index f8c3c446..88d45328 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -235,7 +235,7 @@ int luaF_close (lua_State *L, StkId level, int status) {
235 setobj(L, slot, uv->v); /* move value to upvalue slot */ 235 setobj(L, slot, uv->v); /* move value to upvalue slot */
236 uv->v = slot; /* now current value lives here */ 236 uv->v = slot; /* now current value lives here */
237 if (!iswhite(uv)) { /* neither white nor dead? */ 237 if (!iswhite(uv)) { /* neither white nor dead? */
238 gray2black(uv); /* closed upvalues cannot be gray */ 238 nw2black(uv); /* closed upvalues cannot be gray */
239 luaC_barrier(L, uv, slot); 239 luaC_barrier(L, uv, slot);
240 } 240 }
241 } 241 }
diff --git a/lgc.c b/lgc.c
index 28c31715..be125dd7 100644
--- a/lgc.c
+++ b/lgc.c
@@ -60,19 +60,19 @@
60#define PAUSEADJ 100 60#define PAUSEADJ 100
61 61
62 62
63/* mask to erase all color bits */ 63/* mask with all color bits */
64#define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS)) 64#define maskcolors (bitmask(BLACKBIT) | WHITEBITS)
65 65
66/* mask to erase all GC bits */ 66/* mask with all GC bits */
67#define maskgcbits (maskcolors & ~AGEBITS) 67#define maskgcbits (maskcolors | AGEBITS)
68 68
69 69
70/* macro to erase all color bits then set only the current white bit */ 70/* macro to erase all color bits then set only the current white bit */
71#define makewhite(g,x) \ 71#define makewhite(g,x) \
72 (x->marked = cast_byte((x->marked & maskcolors) | luaC_white(g))) 72 (x->marked = cast_byte((x->marked & ~maskcolors) | luaC_white(g)))
73 73
74#define white2gray(x) resetbits(x->marked, WHITEBITS) 74/* make an object gray (neither white nor black) */
75#define black2gray(x) resetbit(x->marked, BLACKBIT) 75#define set2gray(x) resetbits(x->marked, maskcolors)
76 76
77 77
78#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) 78#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x)))
@@ -221,7 +221,7 @@ void luaC_barrierback_ (lua_State *L, GCObject *o) {
221 lua_assert((g->gckind == KGC_GEN) == (isold(o) && getage(o) != G_TOUCHED1)); 221 lua_assert((g->gckind == KGC_GEN) == (isold(o) && getage(o) != G_TOUCHED1));
222 if (getage(o) != G_TOUCHED2) /* not already in gray list? */ 222 if (getage(o) != G_TOUCHED2) /* not already in gray list? */
223 linkobjgclist(o, g->grayagain); /* link it in 'grayagain' */ 223 linkobjgclist(o, g->grayagain); /* link it in 'grayagain' */
224 black2gray(o); /* make object gray (again) */ 224 set2gray(o); /* make object gray (again) */
225 if (isold(o)) /* generational mode? */ 225 if (isold(o)) /* generational mode? */
226 setage(o, G_TOUCHED1); /* touched in current cycle */ 226 setage(o, G_TOUCHED1); /* touched in current cycle */
227} 227}
@@ -230,7 +230,7 @@ void luaC_barrierback_ (lua_State *L, GCObject *o) {
230void luaC_fix (lua_State *L, GCObject *o) { 230void luaC_fix (lua_State *L, GCObject *o) {
231 global_State *g = G(L); 231 global_State *g = G(L);
232 lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ 232 lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */
233 white2gray(o); /* they will be gray forever */ 233 set2gray(o); /* they will be gray forever */
234 setage(o, G_OLD); /* and old forever */ 234 setage(o, G_OLD); /* and old forever */
235 g->allgc = o->next; /* remove object from 'allgc' list */ 235 g->allgc = o->next; /* remove object from 'allgc' list */
236 o->next = g->fixedgc; /* link it to 'fixedgc' list */ 236 o->next = g->fixedgc; /* link it to 'fixedgc' list */
@@ -272,17 +272,17 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
272** the thread or by 'remarkupvals'.) 272** the thread or by 'remarkupvals'.)
273*/ 273*/
274static void reallymarkobject (global_State *g, GCObject *o) { 274static void reallymarkobject (global_State *g, GCObject *o) {
275 white2gray(o); 275 set2gray(o);
276 switch (o->tt) { 276 switch (o->tt) {
277 case LUA_VSHRSTR: 277 case LUA_VSHRSTR:
278 case LUA_VLNGSTR: { 278 case LUA_VLNGSTR: {
279 gray2black(o); /* nothing to visit */ 279 nw2black(o); /* nothing to visit */
280 break; 280 break;
281 } 281 }
282 case LUA_VUPVAL: { 282 case LUA_VUPVAL: {
283 UpVal *uv = gco2upv(o); 283 UpVal *uv = gco2upv(o);
284 if (!upisopen(uv)) /* open upvalues are kept gray */ 284 if (!upisopen(uv)) /* open upvalues are kept gray */
285 gray2black(o); /* closed upvalues are visited here */ 285 nw2black(o); /* closed upvalues are visited here */
286 markvalue(g, uv->v); /* mark its content */ 286 markvalue(g, uv->v); /* mark its content */
287 break; 287 break;
288 } 288 }
@@ -290,7 +290,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
290 Udata *u = gco2u(o); 290 Udata *u = gco2u(o);
291 if (u->nuvalue == 0) { /* no user values? */ 291 if (u->nuvalue == 0) { /* no user values? */
292 markobjectN(g, u->metatable); /* mark its metatable */ 292 markobjectN(g, u->metatable); /* mark its metatable */
293 gray2black(o); /* nothing else to mark */ 293 nw2black(o); /* nothing else to mark */
294 break; 294 break;
295 } 295 }
296 /* else... */ 296 /* else... */
@@ -412,7 +412,7 @@ static void genlink_ (global_State *g, GCObject *o, GCObject **pnext) {
412 if (getage(o) == G_TOUCHED1) { /* touched in this cycle? */ 412 if (getage(o) == G_TOUCHED1) { /* touched in this cycle? */
413 *pnext = g->grayagain; /* link it back in 'grayagain' */ 413 *pnext = g->grayagain; /* link it back in 'grayagain' */
414 g->grayagain = o; 414 g->grayagain = o;
415 black2gray(o); 415 set2gray(o);
416 } /* everything else do not need to be linked back */ 416 } /* everything else do not need to be linked back */
417 else if (getage(o) == G_TOUCHED2) 417 else if (getage(o) == G_TOUCHED2)
418 changeage(o, G_TOUCHED2, G_OLD); /* advance age */ 418 changeage(o, G_TOUCHED2, G_OLD); /* advance age */
@@ -497,7 +497,7 @@ static int traverseephemeron (global_State *g, Table *h, int inv) {
497 else if (hasclears) /* table has white keys? */ 497 else if (hasclears) /* table has white keys? */
498 linkgclist(h, g->allweak); /* may have to clean white keys */ 498 linkgclist(h, g->allweak); /* may have to clean white keys */
499 else { 499 else {
500 gray2black(h); /* 'genlink' expects black objects */ 500 nw2black(h); /* 'genlink' expects black objects */
501 genlink(g, h); /* check whether collector still needs to see it */ 501 genlink(g, h); /* check whether collector still needs to see it */
502 } 502 }
503 return marked; 503 return marked;
@@ -531,7 +531,7 @@ static lu_mem traversetable (global_State *g, Table *h) {
531 (cast_void(weakkey = strchr(svalue(mode), 'k')), 531 (cast_void(weakkey = strchr(svalue(mode), 'k')),
532 cast_void(weakvalue = strchr(svalue(mode), 'v')), 532 cast_void(weakvalue = strchr(svalue(mode), 'v')),
533 (weakkey || weakvalue))) { /* is really weak? */ 533 (weakkey || weakvalue))) { /* is really weak? */
534 black2gray(h); /* turn it back to gray, as it probably goes to a list */ 534 set2gray(h); /* turn it back to gray, as it probably goes to a list */
535 if (!weakkey) /* strong keys? */ 535 if (!weakkey) /* strong keys? */
536 traverseweakvalue(g, h); 536 traverseweakvalue(g, h);
537 else if (!weakvalue) /* strong values? */ 537 else if (!weakvalue) /* strong values? */
@@ -614,7 +614,7 @@ static int traversethread (global_State *g, lua_State *th) {
614 StkId o = th->stack; 614 StkId o = th->stack;
615 if (isold(th) || g->gcstate == GCSpropagate) { 615 if (isold(th) || g->gcstate == GCSpropagate) {
616 linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ 616 linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
617 black2gray(th); 617 set2gray(th);
618 } 618 }
619 if (o == NULL) 619 if (o == NULL)
620 return 1; /* stack not completely built yet */ 620 return 1; /* stack not completely built yet */
@@ -646,7 +646,7 @@ static int traversethread (global_State *g, lua_State *th) {
646*/ 646*/
647static lu_mem propagatemark (global_State *g) { 647static lu_mem propagatemark (global_State *g) {
648 GCObject *o = g->gray; 648 GCObject *o = g->gray;
649 gray2black(o); 649 nw2black(o);
650 g->gray = *getgclist(o); /* remove from 'gray' list */ 650 g->gray = *getgclist(o); /* remove from 'gray' list */
651 switch (o->tt) { 651 switch (o->tt) {
652 case LUA_VTABLE: return traversetable(g, gco2t(o)); 652 case LUA_VTABLE: return traversetable(g, gco2t(o));
@@ -812,7 +812,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int countin,
812 freeobj(L, curr); /* erase 'curr' */ 812 freeobj(L, curr); /* erase 'curr' */
813 } 813 }
814 else { /* change mark to 'white' */ 814 else { /* change mark to 'white' */
815 curr->marked = cast_byte((marked & maskgcbits) | white); 815 curr->marked = cast_byte((marked & ~maskgcbits) | white);
816 p = &curr->next; /* go to next element */ 816 p = &curr->next; /* go to next element */
817 } 817 }
818 } 818 }
@@ -1048,12 +1048,12 @@ static void sweep2old (lua_State *L, GCObject **p) {
1048 if (curr->tt == LUA_VTHREAD) { /* threads must be watched */ 1048 if (curr->tt == LUA_VTHREAD) { /* threads must be watched */
1049 lua_State *th = gco2th(curr); 1049 lua_State *th = gco2th(curr);
1050 linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ 1050 linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
1051 black2gray(th); /* OK if already gray */ 1051 set2gray(th);
1052 } 1052 }
1053 else if (curr->tt == LUA_VUPVAL && upisopen(gco2upv(curr))) 1053 else if (curr->tt == LUA_VUPVAL && upisopen(gco2upv(curr)))
1054 black2gray(curr); /* open upvalues are always gray */ 1054 set2gray(curr); /* open upvalues are always gray */
1055 else /* everything else is black */ 1055 else /* everything else is black */
1056 gray2black(curr); /* OK if already black */ 1056 nw2black(curr);
1057 p = &curr->next; /* go to next element */ 1057 p = &curr->next; /* go to next element */
1058 } 1058 }
1059 } 1059 }
@@ -1092,7 +1092,7 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
1092 } 1092 }
1093 else { /* correct mark and age */ 1093 else { /* correct mark and age */
1094 if (getage(curr) == G_NEW) { /* new objects go back to white */ 1094 if (getage(curr) == G_NEW) { /* new objects go back to white */
1095 int marked = curr->marked & maskgcbits; /* erase GC bits */ 1095 int marked = curr->marked & ~maskgcbits; /* erase GC bits */
1096 curr->marked = cast_byte(marked | G_SURVIVAL | white); 1096 curr->marked = cast_byte(marked | G_SURVIVAL | white);
1097 } 1097 }
1098 else { /* all other objects will be old, and so keep their color */ 1098 else { /* all other objects will be old, and so keep their color */
@@ -1115,7 +1115,7 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
1115static void whitelist (global_State *g, GCObject *p) { 1115static void whitelist (global_State *g, GCObject *p) {
1116 int white = luaC_white(g); 1116 int white = luaC_white(g);
1117 for (; p != NULL; p = p->next) 1117 for (; p != NULL; p = p->next)
1118 p->marked = cast_byte((p->marked & maskgcbits) | white); 1118 p->marked = cast_byte((p->marked & ~maskgcbits) | white);
1119} 1119}
1120 1120
1121 1121
@@ -1136,7 +1136,7 @@ static GCObject **correctgraylist (GCObject **p) {
1136 goto remove; /* remove all white objects */ 1136 goto remove; /* remove all white objects */
1137 else if (getage(curr) == G_TOUCHED1) { /* touched in this cycle? */ 1137 else if (getage(curr) == G_TOUCHED1) { /* touched in this cycle? */
1138 lua_assert(isgray(curr)); 1138 lua_assert(isgray(curr));
1139 gray2black(curr); /* make it black, for next barrier */ 1139 nw2black(curr); /* make it black, for next barrier */
1140 changeage(curr, G_TOUCHED1, G_TOUCHED2); 1140 changeage(curr, G_TOUCHED1, G_TOUCHED2);
1141 goto remain; /* keep it in the list and go to next element */ 1141 goto remain; /* keep it in the list and go to next element */
1142 } 1142 }
@@ -1148,7 +1148,7 @@ static GCObject **correctgraylist (GCObject **p) {
1148 lua_assert(isold(curr)); /* young objects should be white here */ 1148 lua_assert(isold(curr)); /* young objects should be white here */
1149 if (getage(curr) == G_TOUCHED2) /* advance from TOUCHED2... */ 1149 if (getage(curr) == G_TOUCHED2) /* advance from TOUCHED2... */
1150 changeage(curr, G_TOUCHED2, G_OLD); /* ... to OLD */ 1150 changeage(curr, G_TOUCHED2, G_OLD); /* ... to OLD */
1151 gray2black(curr); /* make object black (to be removed) */ 1151 nw2black(curr); /* make object black (to be removed) */
1152 goto remove; 1152 goto remove;
1153 } 1153 }
1154 remove: *p = *next; continue; 1154 remove: *p = *next; continue;
@@ -1184,7 +1184,7 @@ static void markold (global_State *g, GCObject *from, GCObject *to) {
1184 lua_assert(!iswhite(p)); 1184 lua_assert(!iswhite(p));
1185 changeage(p, G_OLD1, G_OLD); /* now they are old */ 1185 changeage(p, G_OLD1, G_OLD); /* now they are old */
1186 if (isblack(p)) { 1186 if (isblack(p)) {
1187 black2gray(p); /* should be '2white', but gray works too */ 1187 set2gray(p); /* should be '2white', but gray works too */
1188 reallymarkobject(g, p); 1188 reallymarkobject(g, p);
1189 } 1189 }
1190 } 1190 }
diff --git a/lgc.h b/lgc.h
index 0508cd1d..073e2a40 100644
--- a/lgc.h
+++ b/lgc.h
@@ -12,16 +12,16 @@
12#include "lstate.h" 12#include "lstate.h"
13 13
14/* 14/*
15** Collectable objects may have one of three colors: white, which 15** Collectable objects may have one of three colors: white, which means
16** means the object is not marked; gray, which means the 16** the object is not marked; gray, which means the object is marked, but
17** object is marked, but its references may be not marked; and 17** its references may be not marked; and black, which means that the
18** black, which means that the object and all its references are marked. 18** object and all its references are marked. The main invariant of the
19** The main invariant of the garbage collector, while marking objects, 19** garbage collector, while marking objects, is that a black object can
20** is that a black object can never point to a white one. Moreover, 20** never point to a white one. Moreover, any gray object must be in a
21** any gray object must be in a "gray list" (gray, grayagain, weak, 21** "gray list" (gray, grayagain, weak, allweak, ephemeron) so that it
22** allweak, ephemeron) so that it can be visited again before finishing 22** can be visited again before finishing the collection cycle. (Open
23** the collection cycle. These lists have no meaning when the invariant 23** upvalues are an exception to this rule.) These lists have no meaning
24** is not being enforced (e.g., sweep phase). 24** when the invariant is not being enforced (e.g., sweep phase).
25*/ 25*/
26 26
27 27
@@ -96,7 +96,8 @@
96#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked) 96#define isdead(g,v) isdeadm(otherwhite(g), (v)->marked)
97 97
98#define changewhite(x) ((x)->marked ^= WHITEBITS) 98#define changewhite(x) ((x)->marked ^= WHITEBITS)
99#define gray2black(x) l_setbit((x)->marked, BLACKBIT) 99#define nw2black(x) \
100 check_exp(!iswhite(x), l_setbit((x)->marked, BLACKBIT))
100 101
101#define luaC_white(g) cast_byte((g)->currentwhite & WHITEBITS) 102#define luaC_white(g) cast_byte((g)->currentwhite & WHITEBITS)
102 103