|
@@ -348,8 +348,7 @@ static int remarkupvals (global_State *g) {
|
|
int work = 0; /* estimate of how much work was done here */
|
|
int work = 0; /* estimate of how much work was done here */
|
|
while ((thread = *p) != NULL) {
|
|
while ((thread = *p) != NULL) {
|
|
work++;
|
|
work++;
|
|
- lua_assert(!isblack(thread)); /* threads are never black */
|
|
|
|
- if (isgray(thread) && thread->openupval != NULL)
|
|
|
|
|
|
+ if (!iswhite(thread) && thread->openupval != NULL)
|
|
p = &thread->twups; /* keep marked thread with upvalues in the list */
|
|
p = &thread->twups; /* keep marked thread with upvalues in the list */
|
|
else { /* thread is not marked or without upvalues */
|
|
else { /* thread is not marked or without upvalues */
|
|
UpVal *uv;
|
|
UpVal *uv;
|
|
@@ -600,12 +599,23 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
|
|
|
|
|
|
/*
|
|
/*
|
|
** Traverse a thread, marking the elements in the stack up to its top
|
|
** Traverse a thread, marking the elements in the stack up to its top
|
|
-** and cleaning the rest of the stack in the final traversal.
|
|
|
|
-** That ensures that the entire stack have valid (non-dead) objects.
|
|
|
|
|
|
+** and cleaning the rest of the stack in the final traversal. That
|
|
|
|
+** ensures that the entire stack have valid (non-dead) objects.
|
|
|
|
+** Threads have no barriers. In gen. mode, old threads must be visited
|
|
|
|
+** at every cycle, because they might point to young objects. In inc.
|
|
|
|
+** mode, the thread can still be modified before the end of the cycle,
|
|
|
|
+** and therefore it must be visited again in the atomic phase. To ensure
|
|
|
|
+** these visits, threads must return to a gray list if they are not new
|
|
|
|
+** (which can only happen in generational mode) or if the traverse is in
|
|
|
|
+** the propagate phase (which can only happen in incremental mode).
|
|
*/
|
|
*/
|
|
static int traversethread (global_State *g, lua_State *th) {
|
|
static int traversethread (global_State *g, lua_State *th) {
|
|
UpVal *uv;
|
|
UpVal *uv;
|
|
StkId o = th->stack;
|
|
StkId o = th->stack;
|
|
|
|
+ if (isold(th) || g->gcstate == GCSpropagate) {
|
|
|
|
+ linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
|
|
|
|
+ black2gray(th);
|
|
|
|
+ }
|
|
if (o == NULL)
|
|
if (o == NULL)
|
|
return 1; /* stack not completely built yet */
|
|
return 1; /* stack not completely built yet */
|
|
lua_assert(g->gcstate == GCSatomic ||
|
|
lua_assert(g->gcstate == GCSatomic ||
|
|
@@ -644,12 +654,7 @@ static lu_mem propagatemark (global_State *g) {
|
|
case LUA_VLCL: return traverseLclosure(g, gco2lcl(o));
|
|
case LUA_VLCL: return traverseLclosure(g, gco2lcl(o));
|
|
case LUA_VCCL: return traverseCclosure(g, gco2ccl(o));
|
|
case LUA_VCCL: return traverseCclosure(g, gco2ccl(o));
|
|
case LUA_VPROTO: return traverseproto(g, gco2p(o));
|
|
case LUA_VPROTO: return traverseproto(g, gco2p(o));
|
|
- case LUA_VTHREAD: {
|
|
|
|
- lua_State *th = gco2th(o);
|
|
|
|
- linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
|
|
|
|
- black2gray(o);
|
|
|
|
- return traversethread(g, th);
|
|
|
|
- }
|
|
|
|
|
|
+ case LUA_VTHREAD: return traversethread(g, gco2th(o));
|
|
default: lua_assert(0); return 0;
|
|
default: lua_assert(0); return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1028,7 +1033,6 @@ static void setpause (global_State *g);
|
|
** objects and turns the non dead to old. All non-dead threads---which
|
|
** objects and turns the non dead to old. All non-dead threads---which
|
|
** are now old---must be in a gray list. Everything else is not in a
|
|
** are now old---must be in a gray list. Everything else is not in a
|
|
** gray list.
|
|
** gray list.
|
|
-**
|
|
|
|
*/
|
|
*/
|
|
static void sweep2old (lua_State *L, GCObject **p) {
|
|
static void sweep2old (lua_State *L, GCObject **p) {
|
|
GCObject *curr;
|
|
GCObject *curr;
|
|
@@ -1139,10 +1143,16 @@ static GCObject **correctgraylist (GCObject **p) {
|
|
goto remain; /* keep non-white threads on the list */
|
|
goto remain; /* keep non-white threads on the list */
|
|
}
|
|
}
|
|
else { /* everything else is removed */
|
|
else { /* everything else is removed */
|
|
- lua_assert(isold(curr)); /* young objects should be white */
|
|
|
|
- if (getage(curr) == G_TOUCHED2) /* advance from G_TOUCHED2... */
|
|
|
|
- changeage(curr, G_TOUCHED2, G_OLD); /* ... to G_OLD */
|
|
|
|
- gray2black(curr); /* make object black */
|
|
|
|
|
|
+ lua_assert(isold(curr)); /* young objects should be white here */
|
|
|
|
+ if (getage(curr) == G_TOUCHED2) { /* advance from TOUCHED2... */
|
|
|
|
+ changeage(curr, G_TOUCHED2, G_OLD); /* ... to OLD */
|
|
|
|
+ lua_assert(isblack(curr)); /* TOUCHED2 objects are always black */
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ /* everything else in a gray list should be gray */
|
|
|
|
+ lua_assert(isgray(curr));
|
|
|
|
+ gray2black(curr); /* make object black (to be removed) */
|
|
|
|
+ }
|
|
goto remove;
|
|
goto remove;
|
|
}
|
|
}
|
|
remove: *p = *next; continue;
|
|
remove: *p = *next; continue;
|
|
@@ -1207,11 +1217,12 @@ static void youngcollection (lua_State *L, global_State *g) {
|
|
GCObject **psurvival; /* to point to first non-dead survival object */
|
|
GCObject **psurvival; /* to point to first non-dead survival object */
|
|
GCObject *dummy; /* dummy out parameter to 'sweepgen' */
|
|
GCObject *dummy; /* dummy out parameter to 'sweepgen' */
|
|
lua_assert(g->gcstate == GCSpropagate);
|
|
lua_assert(g->gcstate == GCSpropagate);
|
|
- if (g->firstold1) { /* are there OLD1 objects? */
|
|
|
|
|
|
+ if (g->firstold1) { /* are there regular OLD1 objects? */
|
|
markold(g, g->firstold1, g->reallyold); /* mark them */
|
|
markold(g, g->firstold1, g->reallyold); /* mark them */
|
|
g->firstold1 = NULL; /* no more OLD1 objects (for now) */
|
|
g->firstold1 = NULL; /* no more OLD1 objects (for now) */
|
|
}
|
|
}
|
|
markold(g, g->finobj, g->finobjrold);
|
|
markold(g, g->finobj, g->finobjrold);
|
|
|
|
+ markold(g, g->tobefnz, NULL);
|
|
atomic(L);
|
|
atomic(L);
|
|
|
|
|
|
/* sweep nursery and get a pointer to its last live element */
|
|
/* sweep nursery and get a pointer to its last live element */
|
|
@@ -1268,8 +1279,8 @@ static void atomic2gen (lua_State *L, global_State *g) {
|
|
/*
|
|
/*
|
|
** Enter generational mode. Must go until the end of an atomic cycle
|
|
** Enter generational mode. Must go until the end of an atomic cycle
|
|
** to ensure that all objects are correctly marked and weak tables
|
|
** to ensure that all objects are correctly marked and weak tables
|
|
-** are cleared.
|
|
|
|
-** Then, turn all objects into old and finishes the collection.
|
|
|
|
|
|
+** are cleared. Then, turn all objects into old and finishes the
|
|
|
|
+** collection.
|
|
*/
|
|
*/
|
|
static lu_mem entergen (lua_State *L, global_State *g) {
|
|
static lu_mem entergen (lua_State *L, global_State *g) {
|
|
lu_mem numobjs;
|
|
lu_mem numobjs;
|