diff options
| -rw-r--r-- | lgc.c | 47 |
1 files changed, 29 insertions, 18 deletions
| @@ -348,8 +348,7 @@ static int remarkupvals (global_State *g) { | |||
| 348 | int work = 0; /* estimate of how much work was done here */ | 348 | int work = 0; /* estimate of how much work was done here */ |
| 349 | while ((thread = *p) != NULL) { | 349 | while ((thread = *p) != NULL) { |
| 350 | work++; | 350 | work++; |
| 351 | lua_assert(!isblack(thread)); /* threads are never black */ | 351 | if (!iswhite(thread) && thread->openupval != NULL) |
| 352 | if (isgray(thread) && thread->openupval != NULL) | ||
| 353 | p = &thread->twups; /* keep marked thread with upvalues in the list */ | 352 | p = &thread->twups; /* keep marked thread with upvalues in the list */ |
| 354 | else { /* thread is not marked or without upvalues */ | 353 | else { /* thread is not marked or without upvalues */ |
| 355 | UpVal *uv; | 354 | UpVal *uv; |
| @@ -600,12 +599,23 @@ static int traverseLclosure (global_State *g, LClosure *cl) { | |||
| 600 | 599 | ||
| 601 | /* | 600 | /* |
| 602 | ** Traverse a thread, marking the elements in the stack up to its top | 601 | ** Traverse a thread, marking the elements in the stack up to its top |
| 603 | ** and cleaning the rest of the stack in the final traversal. | 602 | ** and cleaning the rest of the stack in the final traversal. That |
| 604 | ** That ensures that the entire stack have valid (non-dead) objects. | 603 | ** ensures that the entire stack have valid (non-dead) objects. |
| 604 | ** Threads have no barriers. In gen. mode, old threads must be visited | ||
| 605 | ** at every cycle, because they might point to young objects. In inc. | ||
| 606 | ** mode, the thread can still be modified before the end of the cycle, | ||
| 607 | ** and therefore it must be visited again in the atomic phase. To ensure | ||
| 608 | ** these visits, threads must return to a gray list if they are not new | ||
| 609 | ** (which can only happen in generational mode) or if the traverse is in | ||
| 610 | ** the propagate phase (which can only happen in incremental mode). | ||
| 605 | */ | 611 | */ |
| 606 | static int traversethread (global_State *g, lua_State *th) { | 612 | static int traversethread (global_State *g, lua_State *th) { |
| 607 | UpVal *uv; | 613 | UpVal *uv; |
| 608 | StkId o = th->stack; | 614 | StkId o = th->stack; |
| 615 | if (isold(th) || g->gcstate == GCSpropagate) { | ||
| 616 | linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ | ||
| 617 | black2gray(th); | ||
| 618 | } | ||
| 609 | if (o == NULL) | 619 | if (o == NULL) |
| 610 | return 1; /* stack not completely built yet */ | 620 | return 1; /* stack not completely built yet */ |
| 611 | lua_assert(g->gcstate == GCSatomic || | 621 | lua_assert(g->gcstate == GCSatomic || |
| @@ -644,12 +654,7 @@ static lu_mem propagatemark (global_State *g) { | |||
| 644 | case LUA_VLCL: return traverseLclosure(g, gco2lcl(o)); | 654 | case LUA_VLCL: return traverseLclosure(g, gco2lcl(o)); |
| 645 | case LUA_VCCL: return traverseCclosure(g, gco2ccl(o)); | 655 | case LUA_VCCL: return traverseCclosure(g, gco2ccl(o)); |
| 646 | case LUA_VPROTO: return traverseproto(g, gco2p(o)); | 656 | case LUA_VPROTO: return traverseproto(g, gco2p(o)); |
| 647 | case LUA_VTHREAD: { | 657 | case LUA_VTHREAD: return traversethread(g, gco2th(o)); |
| 648 | lua_State *th = gco2th(o); | ||
| 649 | linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ | ||
| 650 | black2gray(o); | ||
| 651 | return traversethread(g, th); | ||
| 652 | } | ||
| 653 | default: lua_assert(0); return 0; | 658 | default: lua_assert(0); return 0; |
| 654 | } | 659 | } |
| 655 | } | 660 | } |
| @@ -1028,7 +1033,6 @@ static void setpause (global_State *g); | |||
| 1028 | ** objects and turns the non dead to old. All non-dead threads---which | 1033 | ** objects and turns the non dead to old. All non-dead threads---which |
| 1029 | ** are now old---must be in a gray list. Everything else is not in a | 1034 | ** are now old---must be in a gray list. Everything else is not in a |
| 1030 | ** gray list. | 1035 | ** gray list. |
| 1031 | ** | ||
| 1032 | */ | 1036 | */ |
| 1033 | static void sweep2old (lua_State *L, GCObject **p) { | 1037 | static void sweep2old (lua_State *L, GCObject **p) { |
| 1034 | GCObject *curr; | 1038 | GCObject *curr; |
| @@ -1139,10 +1143,16 @@ static GCObject **correctgraylist (GCObject **p) { | |||
| 1139 | goto remain; /* keep non-white threads on the list */ | 1143 | goto remain; /* keep non-white threads on the list */ |
| 1140 | } | 1144 | } |
| 1141 | else { /* everything else is removed */ | 1145 | else { /* everything else is removed */ |
| 1142 | lua_assert(isold(curr)); /* young objects should be white */ | 1146 | lua_assert(isold(curr)); /* young objects should be white here */ |
| 1143 | if (getage(curr) == G_TOUCHED2) /* advance from G_TOUCHED2... */ | 1147 | if (getage(curr) == G_TOUCHED2) { /* advance from TOUCHED2... */ |
| 1144 | changeage(curr, G_TOUCHED2, G_OLD); /* ... to G_OLD */ | 1148 | changeage(curr, G_TOUCHED2, G_OLD); /* ... to OLD */ |
| 1145 | gray2black(curr); /* make object black */ | 1149 | lua_assert(isblack(curr)); /* TOUCHED2 objects are always black */ |
| 1150 | } | ||
| 1151 | else { | ||
| 1152 | /* everything else in a gray list should be gray */ | ||
| 1153 | lua_assert(isgray(curr)); | ||
| 1154 | gray2black(curr); /* make object black (to be removed) */ | ||
| 1155 | } | ||
| 1146 | goto remove; | 1156 | goto remove; |
| 1147 | } | 1157 | } |
| 1148 | remove: *p = *next; continue; | 1158 | remove: *p = *next; continue; |
| @@ -1207,11 +1217,12 @@ static void youngcollection (lua_State *L, global_State *g) { | |||
| 1207 | GCObject **psurvival; /* to point to first non-dead survival object */ | 1217 | GCObject **psurvival; /* to point to first non-dead survival object */ |
| 1208 | GCObject *dummy; /* dummy out parameter to 'sweepgen' */ | 1218 | GCObject *dummy; /* dummy out parameter to 'sweepgen' */ |
| 1209 | lua_assert(g->gcstate == GCSpropagate); | 1219 | lua_assert(g->gcstate == GCSpropagate); |
| 1210 | if (g->firstold1) { /* are there OLD1 objects? */ | 1220 | if (g->firstold1) { /* are there regular OLD1 objects? */ |
| 1211 | markold(g, g->firstold1, g->reallyold); /* mark them */ | 1221 | markold(g, g->firstold1, g->reallyold); /* mark them */ |
| 1212 | g->firstold1 = NULL; /* no more OLD1 objects (for now) */ | 1222 | g->firstold1 = NULL; /* no more OLD1 objects (for now) */ |
| 1213 | } | 1223 | } |
| 1214 | markold(g, g->finobj, g->finobjrold); | 1224 | markold(g, g->finobj, g->finobjrold); |
| 1225 | markold(g, g->tobefnz, NULL); | ||
| 1215 | atomic(L); | 1226 | atomic(L); |
| 1216 | 1227 | ||
| 1217 | /* sweep nursery and get a pointer to its last live element */ | 1228 | /* sweep nursery and get a pointer to its last live element */ |
| @@ -1268,8 +1279,8 @@ static void atomic2gen (lua_State *L, global_State *g) { | |||
| 1268 | /* | 1279 | /* |
| 1269 | ** Enter generational mode. Must go until the end of an atomic cycle | 1280 | ** Enter generational mode. Must go until the end of an atomic cycle |
| 1270 | ** to ensure that all objects are correctly marked and weak tables | 1281 | ** to ensure that all objects are correctly marked and weak tables |
| 1271 | ** are cleared. | 1282 | ** are cleared. Then, turn all objects into old and finishes the |
| 1272 | ** Then, turn all objects into old and finishes the collection. | 1283 | ** collection. |
| 1273 | */ | 1284 | */ |
| 1274 | static lu_mem entergen (lua_State *L, global_State *g) { | 1285 | static lu_mem entergen (lua_State *L, global_State *g) { |
| 1275 | lu_mem numobjs; | 1286 | lu_mem numobjs; |
