diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-12-07 15:45:41 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-12-07 15:45:41 -0300 |
commit | ad73b332240ef5b9bab1517517f63a1425dc7545 (patch) | |
tree | f16bc7d4e498e009dbd83e1988b0d203129724cb /lgc.c | |
parent | 925fe8a0f2a667c96c015ee74d1a702af9ea5507 (diff) | |
download | lua-ad73b332240ef5b9bab1517517f63a1425dc7545.tar.gz lua-ad73b332240ef5b9bab1517517f63a1425dc7545.tar.bz2 lua-ad73b332240ef5b9bab1517517f63a1425dc7545.zip |
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.
Diffstat (limited to 'lgc.c')
-rw-r--r-- | lgc.c | 95 |
1 files changed, 35 insertions, 60 deletions
@@ -1098,7 +1098,8 @@ static void sweep2old (lua_State *L, GCObject **p) { | |||
1098 | ** will also remove objects turned white here from any gray list. | 1098 | ** will also remove objects turned white here from any gray list. |
1099 | */ | 1099 | */ |
1100 | static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, | 1100 | static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, |
1101 | GCObject *limit, GCObject **pfirstold1) { | 1101 | GCObject *limit, GCObject **pfirstold1, |
1102 | l_obj *paddedold) { | ||
1102 | static const lu_byte nextage[] = { | 1103 | static const lu_byte nextage[] = { |
1103 | G_SURVIVAL, /* from G_NEW */ | 1104 | G_SURVIVAL, /* from G_NEW */ |
1104 | G_OLD1, /* from G_SURVIVAL */ | 1105 | G_OLD1, /* from G_SURVIVAL */ |
@@ -1108,6 +1109,7 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, | |||
1108 | G_TOUCHED1, /* from G_TOUCHED1 (do not change) */ | 1109 | G_TOUCHED1, /* from G_TOUCHED1 (do not change) */ |
1109 | G_TOUCHED2 /* from G_TOUCHED2 (do not change) */ | 1110 | G_TOUCHED2 /* from G_TOUCHED2 (do not change) */ |
1110 | }; | 1111 | }; |
1112 | l_obj addedold = 0; | ||
1111 | int white = luaC_white(g); | 1113 | int white = luaC_white(g); |
1112 | GCObject *curr; | 1114 | GCObject *curr; |
1113 | while ((curr = *p) != limit) { | 1115 | while ((curr = *p) != limit) { |
@@ -1125,29 +1127,21 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, | |||
1125 | else { /* all other objects will be old, and so keep their color */ | 1127 | else { /* all other objects will be old, and so keep their color */ |
1126 | lua_assert(age != G_OLD1); /* advanced in 'markold' */ | 1128 | lua_assert(age != G_OLD1); /* advanced in 'markold' */ |
1127 | setage(curr, nextage[age]); | 1129 | setage(curr, nextage[age]); |
1128 | if (getage(curr) == G_OLD1 && *pfirstold1 == NULL) | 1130 | if (getage(curr) == G_OLD1) { |
1129 | *pfirstold1 = curr; /* first OLD1 object in the list */ | 1131 | addedold++; /* one more object becoming old */ |
1132 | if (*pfirstold1 == NULL) | ||
1133 | *pfirstold1 = curr; /* first OLD1 object in the list */ | ||
1134 | } | ||
1130 | } | 1135 | } |
1131 | p = &curr->next; /* go to next element */ | 1136 | p = &curr->next; /* go to next element */ |
1132 | } | 1137 | } |
1133 | } | 1138 | } |
1139 | *paddedold += addedold; | ||
1134 | return p; | 1140 | return p; |
1135 | } | 1141 | } |
1136 | 1142 | ||
1137 | 1143 | ||
1138 | /* | 1144 | /* |
1139 | ** Traverse a list making all its elements white and clearing their | ||
1140 | ** age. In incremental mode, all objects are 'new' all the time, | ||
1141 | ** except for fixed strings (which are always old). | ||
1142 | */ | ||
1143 | static void whitelist (global_State *g, GCObject *p) { | ||
1144 | int white = luaC_white(g); | ||
1145 | for (; p != NULL; p = p->next) | ||
1146 | p->marked = cast_byte((p->marked & ~maskgcbits) | white); | ||
1147 | } | ||
1148 | |||
1149 | |||
1150 | /* | ||
1151 | ** Correct a list of gray objects. Return a pointer to the last element | 1145 | ** Correct a list of gray objects. Return a pointer to the last element |
1152 | ** left on the list, so that we can link another list to the end of | 1146 | ** left on the list, so that we can link another list to the end of |
1153 | ** this one. | 1147 | ** this one. |
@@ -1205,21 +1199,18 @@ static void correctgraylists (global_State *g) { | |||
1205 | /* | 1199 | /* |
1206 | ** Mark black 'OLD1' objects when starting a new young collection. | 1200 | ** Mark black 'OLD1' objects when starting a new young collection. |
1207 | ** Gray objects are already in some gray list, and so will be visited in | 1201 | ** Gray objects are already in some gray list, and so will be visited in |
1208 | ** the atomic step. Returns the number of objects that became old. | 1202 | ** the atomic step. |
1209 | */ | 1203 | */ |
1210 | static l_obj markold (global_State *g, GCObject *from, GCObject *to) { | 1204 | static void markold (global_State *g, GCObject *from, GCObject *to) { |
1211 | GCObject *p; | 1205 | GCObject *p; |
1212 | l_obj count = 0; | ||
1213 | for (p = from; p != to; p = p->next) { | 1206 | for (p = from; p != to; p = p->next) { |
1214 | if (getage(p) == G_OLD1) { | 1207 | if (getage(p) == G_OLD1) { |
1215 | lua_assert(!iswhite(p)); | 1208 | lua_assert(!iswhite(p)); |
1216 | setage(p, G_OLD); /* now they are old */ | 1209 | setage(p, G_OLD); /* now they are old */ |
1217 | count++; /* one more old object */ | ||
1218 | if (isblack(p)) | 1210 | if (isblack(p)) |
1219 | reallymarkobject(g, p); | 1211 | reallymarkobject(g, p); |
1220 | } | 1212 | } |
1221 | } | 1213 | } |
1222 | return count; | ||
1223 | } | 1214 | } |
1224 | 1215 | ||
1225 | 1216 | ||
@@ -1236,16 +1227,17 @@ static void finishgencycle (lua_State *L, global_State *g) { | |||
1236 | 1227 | ||
1237 | 1228 | ||
1238 | /* | 1229 | /* |
1239 | ** shifts from the end of an atomic step in a minor collection to | 1230 | ** Shifts from a minor collection to major collections. It starts in |
1240 | ** major collections. | 1231 | ** the "sweep all" state to clear all objects, which are mostly black |
1232 | ** in generational mode. | ||
1241 | */ | 1233 | */ |
1242 | static void atomic2major (lua_State *L, global_State *g) { | 1234 | static void minor2inc (lua_State *L, global_State *g, int kind) { |
1243 | l_obj stepsize = cast(l_obj, 1) << g->gcstepsize; | 1235 | l_obj stepsize = cast(l_obj, 1) << g->gcstepsize; |
1244 | g->GCmajorminor = g->marked; /* number of live objects */ | 1236 | g->GCmajorminor = g->marked; /* number of live objects */ |
1245 | g->gckind = KGC_GENMAJOR; | 1237 | g->gckind = kind; |
1246 | g->reallyold = g->old1 = g->survival = NULL; | 1238 | g->reallyold = g->old1 = g->survival = NULL; |
1247 | g->finobjrold = g->finobjold1 = g->finobjsur = NULL; | 1239 | g->finobjrold = g->finobjold1 = g->finobjsur = NULL; |
1248 | entersweep(L); /* continue from atomic as an incremental cycle */ | 1240 | entersweep(L); /* continue as an incremental cycle */ |
1249 | luaE_setdebt(g, stepsize); | 1241 | luaE_setdebt(g, stepsize); |
1250 | } | 1242 | } |
1251 | 1243 | ||
@@ -1266,7 +1258,7 @@ static int checkminormajor (lua_State *L, global_State *g, l_obj addedold1) { | |||
1266 | l_obj limit = applygcparam(g, minormajor, g->GCmajorminor); | 1258 | l_obj limit = applygcparam(g, minormajor, g->GCmajorminor); |
1267 | //printf("-> major? %ld %ld %ld %ld (%ld)\n", g->marked, limit, step, addedold1, gettotalobjs(g)); | 1259 | //printf("-> major? %ld %ld %ld %ld (%ld)\n", g->marked, limit, step, addedold1, gettotalobjs(g)); |
1268 | if (addedold1 >= (step >> 1) || g->marked >= limit) { | 1260 | if (addedold1 >= (step >> 1) || g->marked >= limit) { |
1269 | atomic2major(L, g); /* go to major mode */ | 1261 | minor2inc(L, g, KGC_GENMAJOR); /* go to major mode */ |
1270 | return 1; | 1262 | return 1; |
1271 | } | 1263 | } |
1272 | return 0; /* stay in minor mode */ | 1264 | return 0; /* stay in minor mode */ |
@@ -1284,41 +1276,40 @@ static void youngcollection (lua_State *L, global_State *g) { | |||
1284 | GCObject *dummy; /* dummy out parameter to 'sweepgen' */ | 1276 | GCObject *dummy; /* dummy out parameter to 'sweepgen' */ |
1285 | lua_assert(g->gcstate == GCSpropagate); | 1277 | lua_assert(g->gcstate == GCSpropagate); |
1286 | if (g->firstold1) { /* are there regular OLD1 objects? */ | 1278 | if (g->firstold1) { /* are there regular OLD1 objects? */ |
1287 | addedold1 += markold(g, g->firstold1, g->reallyold); /* mark them */ | 1279 | markold(g, g->firstold1, g->reallyold); /* mark them */ |
1288 | g->firstold1 = NULL; /* no more OLD1 objects (for now) */ | 1280 | g->firstold1 = NULL; /* no more OLD1 objects (for now) */ |
1289 | } | 1281 | } |
1290 | addedold1 += markold(g, g->finobj, g->finobjrold); | 1282 | markold(g, g->finobj, g->finobjrold); |
1291 | addedold1 += markold(g, g->tobefnz, NULL); | 1283 | markold(g, g->tobefnz, NULL); |
1292 | 1284 | ||
1293 | atomic(L); /* will lose 'g->marked' */ | 1285 | atomic(L); /* will lose 'g->marked' */ |
1294 | 1286 | ||
1295 | /* keep total number of added old1 objects */ | ||
1296 | g->marked = marked + addedold1; | ||
1297 | |||
1298 | /* decide whether to shift to major mode */ | ||
1299 | if (checkminormajor(L, g, addedold1)) | ||
1300 | return; /* nothing else to be done here */ | ||
1301 | |||
1302 | /* sweep nursery and get a pointer to its last live element */ | 1287 | /* sweep nursery and get a pointer to its last live element */ |
1303 | g->gcstate = GCSswpallgc; | 1288 | g->gcstate = GCSswpallgc; |
1304 | psurvival = sweepgen(L, g, &g->allgc, g->survival, &g->firstold1); | 1289 | psurvival = sweepgen(L, g, &g->allgc, g->survival, &g->firstold1, &addedold1); |
1305 | /* sweep 'survival' */ | 1290 | /* sweep 'survival' */ |
1306 | sweepgen(L, g, psurvival, g->old1, &g->firstold1); | 1291 | sweepgen(L, g, psurvival, g->old1, &g->firstold1, &addedold1); |
1307 | g->reallyold = g->old1; | 1292 | g->reallyold = g->old1; |
1308 | g->old1 = *psurvival; /* 'survival' survivals are old now */ | 1293 | g->old1 = *psurvival; /* 'survival' survivals are old now */ |
1309 | g->survival = g->allgc; /* all news are survivals */ | 1294 | g->survival = g->allgc; /* all news are survivals */ |
1310 | 1295 | ||
1311 | /* repeat for 'finobj' lists */ | 1296 | /* repeat for 'finobj' lists */ |
1312 | dummy = NULL; /* no 'firstold1' optimization for 'finobj' lists */ | 1297 | dummy = NULL; /* no 'firstold1' optimization for 'finobj' lists */ |
1313 | psurvival = sweepgen(L, g, &g->finobj, g->finobjsur, &dummy); | 1298 | psurvival = sweepgen(L, g, &g->finobj, g->finobjsur, &dummy, &addedold1); |
1314 | /* sweep 'survival' */ | 1299 | /* sweep 'survival' */ |
1315 | sweepgen(L, g, psurvival, g->finobjold1, &dummy); | 1300 | sweepgen(L, g, psurvival, g->finobjold1, &dummy, &addedold1); |
1316 | g->finobjrold = g->finobjold1; | 1301 | g->finobjrold = g->finobjold1; |
1317 | g->finobjold1 = *psurvival; /* 'survival' survivals are old now */ | 1302 | g->finobjold1 = *psurvival; /* 'survival' survivals are old now */ |
1318 | g->finobjsur = g->finobj; /* all news are survivals */ | 1303 | g->finobjsur = g->finobj; /* all news are survivals */ |
1319 | 1304 | ||
1320 | sweepgen(L, g, &g->tobefnz, NULL, &dummy); | 1305 | sweepgen(L, g, &g->tobefnz, NULL, &dummy, &addedold1); |
1321 | finishgencycle(L, g); | 1306 | |
1307 | /* keep total number of added old1 objects */ | ||
1308 | g->marked = marked + addedold1; | ||
1309 | |||
1310 | /* decide whether to shift to major mode */ | ||
1311 | if (!checkminormajor(L, g, addedold1)) | ||
1312 | finishgencycle(L, g); /* still in minor mode; finish it */ | ||
1322 | } | 1313 | } |
1323 | 1314 | ||
1324 | 1315 | ||
@@ -1375,22 +1366,6 @@ static void entergen (lua_State *L, global_State *g) { | |||
1375 | 1366 | ||
1376 | 1367 | ||
1377 | /* | 1368 | /* |
1378 | ** Enter incremental mode. Turn all objects white, make all | ||
1379 | ** intermediate lists point to NULL (to avoid invalid pointers), | ||
1380 | ** and go to the pause state. | ||
1381 | */ | ||
1382 | static void enterinc (global_State *g) { | ||
1383 | whitelist(g, g->allgc); | ||
1384 | whitelist(g, g->finobj); | ||
1385 | whitelist(g, g->tobefnz); | ||
1386 | g->reallyold = g->old1 = g->survival = NULL; | ||
1387 | g->finobjrold = g->finobjold1 = g->finobjsur = NULL; | ||
1388 | g->gcstate = GCSpause; | ||
1389 | g->gckind = KGC_INC; | ||
1390 | } | ||
1391 | |||
1392 | |||
1393 | /* | ||
1394 | ** Change collector mode to 'newmode'. | 1369 | ** Change collector mode to 'newmode'. |
1395 | */ | 1370 | */ |
1396 | void luaC_changemode (lua_State *L, int newmode) { | 1371 | void luaC_changemode (lua_State *L, int newmode) { |
@@ -1399,7 +1374,7 @@ void luaC_changemode (lua_State *L, int newmode) { | |||
1399 | g->gckind = KGC_INC; /* already incremental but in name */ | 1374 | g->gckind = KGC_INC; /* already incremental but in name */ |
1400 | if (newmode != g->gckind) { /* does it need to change? */ | 1375 | if (newmode != g->gckind) { /* does it need to change? */ |
1401 | if (newmode == KGC_INC) /* entering incremental mode? */ | 1376 | if (newmode == KGC_INC) /* entering incremental mode? */ |
1402 | enterinc(g); /* entering incremental mode */ | 1377 | minor2inc(L, g, KGC_INC); /* entering incremental mode */ |
1403 | else { | 1378 | else { |
1404 | lua_assert(newmode == KGC_GENMINOR); | 1379 | lua_assert(newmode == KGC_GENMINOR); |
1405 | entergen(L, g); | 1380 | entergen(L, g); |
@@ -1412,7 +1387,7 @@ void luaC_changemode (lua_State *L, int newmode) { | |||
1412 | ** Does a full collection in generational mode. | 1387 | ** Does a full collection in generational mode. |
1413 | */ | 1388 | */ |
1414 | static void fullgen (lua_State *L, global_State *g) { | 1389 | static void fullgen (lua_State *L, global_State *g) { |
1415 | enterinc(g); | 1390 | minor2inc(L, g, KGC_INC); |
1416 | entergen(L, g); | 1391 | entergen(L, g); |
1417 | } | 1392 | } |
1418 | 1393 | ||