diff options
-rw-r--r-- | lfunc.c | 2 | ||||
-rw-r--r-- | lgc.c | 54 | ||||
-rw-r--r-- | lgc.h | 23 |
3 files changed, 40 insertions, 39 deletions
@@ -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 | } |
@@ -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) { | |||
230 | void luaC_fix (lua_State *L, GCObject *o) { | 230 | void 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 | */ |
274 | static void reallymarkobject (global_State *g, GCObject *o) { | 274 | static 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 | */ |
647 | static lu_mem propagatemark (global_State *g) { | 647 | static 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, | |||
1115 | static void whitelist (global_State *g, GCObject *p) { | 1115 | static 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 | } |
@@ -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 | ||