Check minor->major made at the end of a minor cycle

It does not make sense to wait for another cycle to decide when much of
the information about creation of old objects is already available.
This commit is contained in:
Roberto Ierusalimschy 2023-12-07 15:45:41 -03:00
parent 925fe8a0f2
commit ad73b33224

95
lgc.c
View File

@ -1098,7 +1098,8 @@ static void sweep2old (lua_State *L, GCObject **p) {
** will also remove objects turned white here from any gray list.
*/
static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
GCObject *limit, GCObject **pfirstold1) {
GCObject *limit, GCObject **pfirstold1,
l_obj *paddedold) {
static const lu_byte nextage[] = {
G_SURVIVAL, /* from G_NEW */
G_OLD1, /* from G_SURVIVAL */
@ -1108,6 +1109,7 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
G_TOUCHED1, /* from G_TOUCHED1 (do not change) */
G_TOUCHED2 /* from G_TOUCHED2 (do not change) */
};
l_obj addedold = 0;
int white = luaC_white(g);
GCObject *curr;
while ((curr = *p) != limit) {
@ -1125,28 +1127,20 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
else { /* all other objects will be old, and so keep their color */
lua_assert(age != G_OLD1); /* advanced in 'markold' */
setage(curr, nextage[age]);
if (getage(curr) == G_OLD1 && *pfirstold1 == NULL)
*pfirstold1 = curr; /* first OLD1 object in the list */
if (getage(curr) == G_OLD1) {
addedold++; /* one more object becoming old */
if (*pfirstold1 == NULL)
*pfirstold1 = curr; /* first OLD1 object in the list */
}
}
p = &curr->next; /* go to next element */
}
}
*paddedold += addedold;
return p;
}
/*
** Traverse a list making all its elements white and clearing their
** age. In incremental mode, all objects are 'new' all the time,
** except for fixed strings (which are always old).
*/
static void whitelist (global_State *g, GCObject *p) {
int white = luaC_white(g);
for (; p != NULL; p = p->next)
p->marked = cast_byte((p->marked & ~maskgcbits) | white);
}
/*
** Correct a list of gray objects. Return a pointer to the last element
** left on the list, so that we can link another list to the end of
@ -1205,21 +1199,18 @@ static void correctgraylists (global_State *g) {
/*
** Mark black 'OLD1' objects when starting a new young collection.
** Gray objects are already in some gray list, and so will be visited in
** the atomic step. Returns the number of objects that became old.
** the atomic step.
*/
static l_obj markold (global_State *g, GCObject *from, GCObject *to) {
static void markold (global_State *g, GCObject *from, GCObject *to) {
GCObject *p;
l_obj count = 0;
for (p = from; p != to; p = p->next) {
if (getage(p) == G_OLD1) {
lua_assert(!iswhite(p));
setage(p, G_OLD); /* now they are old */
count++; /* one more old object */
if (isblack(p))
reallymarkobject(g, p);
}
}
return count;
}
@ -1236,16 +1227,17 @@ static void finishgencycle (lua_State *L, global_State *g) {
/*
** shifts from the end of an atomic step in a minor collection to
** major collections.
** Shifts from a minor collection to major collections. It starts in
** the "sweep all" state to clear all objects, which are mostly black
** in generational mode.
*/
static void atomic2major (lua_State *L, global_State *g) {
static void minor2inc (lua_State *L, global_State *g, int kind) {
l_obj stepsize = cast(l_obj, 1) << g->gcstepsize;
g->GCmajorminor = g->marked; /* number of live objects */
g->gckind = KGC_GENMAJOR;
g->gckind = kind;
g->reallyold = g->old1 = g->survival = NULL;
g->finobjrold = g->finobjold1 = g->finobjsur = NULL;
entersweep(L); /* continue from atomic as an incremental cycle */
entersweep(L); /* continue as an incremental cycle */
luaE_setdebt(g, stepsize);
}
@ -1266,7 +1258,7 @@ static int checkminormajor (lua_State *L, global_State *g, l_obj addedold1) {
l_obj limit = applygcparam(g, minormajor, g->GCmajorminor);
//printf("-> major? %ld %ld %ld %ld (%ld)\n", g->marked, limit, step, addedold1, gettotalobjs(g));
if (addedold1 >= (step >> 1) || g->marked >= limit) {
atomic2major(L, g); /* go to major mode */
minor2inc(L, g, KGC_GENMAJOR); /* go to major mode */
return 1;
}
return 0; /* stay in minor mode */
@ -1284,41 +1276,40 @@ static void youngcollection (lua_State *L, global_State *g) {
GCObject *dummy; /* dummy out parameter to 'sweepgen' */
lua_assert(g->gcstate == GCSpropagate);
if (g->firstold1) { /* are there regular OLD1 objects? */
addedold1 += 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) */
}
addedold1 += markold(g, g->finobj, g->finobjrold);
addedold1 += markold(g, g->tobefnz, NULL);
markold(g, g->finobj, g->finobjrold);
markold(g, g->tobefnz, NULL);
atomic(L); /* will lose 'g->marked' */
/* keep total number of added old1 objects */
g->marked = marked + addedold1;
/* decide whether to shift to major mode */
if (checkminormajor(L, g, addedold1))
return; /* nothing else to be done here */
/* sweep nursery and get a pointer to its last live element */
g->gcstate = GCSswpallgc;
psurvival = sweepgen(L, g, &g->allgc, g->survival, &g->firstold1);
psurvival = sweepgen(L, g, &g->allgc, g->survival, &g->firstold1, &addedold1);
/* sweep 'survival' */
sweepgen(L, g, psurvival, g->old1, &g->firstold1);
sweepgen(L, g, psurvival, g->old1, &g->firstold1, &addedold1);
g->reallyold = g->old1;
g->old1 = *psurvival; /* 'survival' survivals are old now */
g->survival = g->allgc; /* all news are survivals */
/* repeat for 'finobj' lists */
dummy = NULL; /* no 'firstold1' optimization for 'finobj' lists */
psurvival = sweepgen(L, g, &g->finobj, g->finobjsur, &dummy);
psurvival = sweepgen(L, g, &g->finobj, g->finobjsur, &dummy, &addedold1);
/* sweep 'survival' */
sweepgen(L, g, psurvival, g->finobjold1, &dummy);
sweepgen(L, g, psurvival, g->finobjold1, &dummy, &addedold1);
g->finobjrold = g->finobjold1;
g->finobjold1 = *psurvival; /* 'survival' survivals are old now */
g->finobjsur = g->finobj; /* all news are survivals */
sweepgen(L, g, &g->tobefnz, NULL, &dummy);
finishgencycle(L, g);
sweepgen(L, g, &g->tobefnz, NULL, &dummy, &addedold1);
/* keep total number of added old1 objects */
g->marked = marked + addedold1;
/* decide whether to shift to major mode */
if (!checkminormajor(L, g, addedold1))
finishgencycle(L, g); /* still in minor mode; finish it */
}
@ -1374,22 +1365,6 @@ static void entergen (lua_State *L, global_State *g) {
}
/*
** Enter incremental mode. Turn all objects white, make all
** intermediate lists point to NULL (to avoid invalid pointers),
** and go to the pause state.
*/
static void enterinc (global_State *g) {
whitelist(g, g->allgc);
whitelist(g, g->finobj);
whitelist(g, g->tobefnz);
g->reallyold = g->old1 = g->survival = NULL;
g->finobjrold = g->finobjold1 = g->finobjsur = NULL;
g->gcstate = GCSpause;
g->gckind = KGC_INC;
}
/*
** Change collector mode to 'newmode'.
*/
@ -1399,7 +1374,7 @@ void luaC_changemode (lua_State *L, int newmode) {
g->gckind = KGC_INC; /* already incremental but in name */
if (newmode != g->gckind) { /* does it need to change? */
if (newmode == KGC_INC) /* entering incremental mode? */
enterinc(g); /* entering incremental mode */
minor2inc(L, g, KGC_INC); /* entering incremental mode */
else {
lua_assert(newmode == KGC_GENMINOR);
entergen(L, g);
@ -1412,7 +1387,7 @@ void luaC_changemode (lua_State *L, int newmode) {
** Does a full collection in generational mode.
*/
static void fullgen (lua_State *L, global_State *g) {
enterinc(g);
minor2inc(L, g, KGC_INC);
entergen(L, g);
}