diff options
Diffstat (limited to 'lgc.c')
-rw-r--r-- | lgc.c | 141 |
1 files changed, 73 insertions, 68 deletions
@@ -206,7 +206,7 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { | |||
206 | } | 206 | } |
207 | else { /* sweep phase */ | 207 | else { /* sweep phase */ |
208 | lua_assert(issweepphase(g)); | 208 | lua_assert(issweepphase(g)); |
209 | if (g->gckind != KGC_GEN) /* incremental mode? */ | 209 | if (g->gckind != KGC_GENMINOR) /* incremental mode? */ |
210 | makewhite(g, o); /* mark 'o' as white to avoid other barriers */ | 210 | makewhite(g, o); /* mark 'o' as white to avoid other barriers */ |
211 | } | 211 | } |
212 | } | 212 | } |
@@ -219,7 +219,8 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { | |||
219 | void luaC_barrierback_ (lua_State *L, GCObject *o) { | 219 | void luaC_barrierback_ (lua_State *L, GCObject *o) { |
220 | global_State *g = G(L); | 220 | global_State *g = G(L); |
221 | lua_assert(isblack(o) && !isdead(g, o)); | 221 | lua_assert(isblack(o) && !isdead(g, o)); |
222 | lua_assert((g->gckind == KGC_GEN) == (isold(o) && getage(o) != G_TOUCHED1)); | 222 | lua_assert((g->gckind != KGC_GENMINOR) |
223 | || (isold(o) && getage(o) != G_TOUCHED1)); | ||
223 | if (getage(o) == G_TOUCHED2) /* already in gray list? */ | 224 | if (getage(o) == G_TOUCHED2) /* already in gray list? */ |
224 | set2gray(o); /* make it gray to become touched1 */ | 225 | set2gray(o); /* make it gray to become touched1 */ |
225 | else /* link it in 'grayagain' and paint it gray */ | 226 | else /* link it in 'grayagain' and paint it gray */ |
@@ -1116,13 +1117,14 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, | |||
1116 | freeobj(L, curr); /* erase 'curr' */ | 1117 | freeobj(L, curr); /* erase 'curr' */ |
1117 | } | 1118 | } |
1118 | else { /* correct mark and age */ | 1119 | else { /* correct mark and age */ |
1119 | if (getage(curr) == G_NEW) { /* new objects go back to white */ | 1120 | int age = getage(curr); |
1121 | if (age == G_NEW) { /* new objects go back to white */ | ||
1120 | int marked = curr->marked & ~maskgcbits; /* erase GC bits */ | 1122 | int marked = curr->marked & ~maskgcbits; /* erase GC bits */ |
1121 | curr->marked = cast_byte(marked | G_SURVIVAL | white); | 1123 | curr->marked = cast_byte(marked | G_SURVIVAL | white); |
1122 | } | 1124 | } |
1123 | else { /* all other objects will be old, and so keep their color */ | 1125 | else { /* all other objects will be old, and so keep their color */ |
1124 | lua_assert(getage(curr) != G_OLD1); /* advanced in 'markold' */ | 1126 | lua_assert(age != G_OLD1); /* advanced in 'markold' */ |
1125 | setage(curr, nextage[getage(curr)]); | 1127 | setage(curr, nextage[age]); |
1126 | if (getage(curr) == G_OLD1 && *pfirstold1 == NULL) | 1128 | if (getage(curr) == G_OLD1 && *pfirstold1 == NULL) |
1127 | *pfirstold1 = curr; /* first OLD1 object in the list */ | 1129 | *pfirstold1 = curr; /* first OLD1 object in the list */ |
1128 | } | 1130 | } |
@@ -1202,8 +1204,9 @@ static void correctgraylists (global_State *g) { | |||
1202 | 1204 | ||
1203 | /* | 1205 | /* |
1204 | ** Mark black 'OLD1' objects when starting a new young collection. | 1206 | ** Mark black 'OLD1' objects when starting a new young collection. |
1205 | ** Gray objects are already in some gray list, and so will be visited | 1207 | ** Gray objects are already in some gray list, and so will be visited in |
1206 | ** in the atomic step. | 1208 | ** the atomic step. The counter 'GCmajorminor' keeps how many objects to |
1209 | ** become old before a major collection. | ||
1207 | */ | 1210 | */ |
1208 | static void markold (global_State *g, GCObject *from, GCObject *to) { | 1211 | static void markold (global_State *g, GCObject *from, GCObject *to) { |
1209 | GCObject *p; | 1212 | GCObject *p; |
@@ -1211,6 +1214,7 @@ static void markold (global_State *g, GCObject *from, GCObject *to) { | |||
1211 | if (getage(p) == G_OLD1) { | 1214 | if (getage(p) == G_OLD1) { |
1212 | lua_assert(!iswhite(p)); | 1215 | lua_assert(!iswhite(p)); |
1213 | setage(p, G_OLD); /* now they are old */ | 1216 | setage(p, G_OLD); /* now they are old */ |
1217 | g->GCmajorminor--; /* one more old object */ | ||
1214 | if (isblack(p)) | 1218 | if (isblack(p)) |
1215 | reallymarkobject(g, p); | 1219 | reallymarkobject(g, p); |
1216 | } | 1220 | } |
@@ -1231,22 +1235,45 @@ static void finishgencycle (lua_State *L, global_State *g) { | |||
1231 | 1235 | ||
1232 | 1236 | ||
1233 | /* | 1237 | /* |
1238 | ** shifts from the end of an atomic step in a minor collection to | ||
1239 | ** major collections. | ||
1240 | */ | ||
1241 | static void atomic2major (lua_State *L, global_State *g) { | ||
1242 | l_obj stepsize = cast(l_obj, 1) << g->gcstepsize; | ||
1243 | g->GCmajorminor = gettotalobjs(g); | ||
1244 | g->gckind = KGC_GENMAJOR; | ||
1245 | g->reallyold = g->old1 = g->survival = NULL; | ||
1246 | g->finobjrold = g->finobjold1 = g->finobjsur = NULL; | ||
1247 | entersweep(L); /* continue from atomic as an incremental cycle */ | ||
1248 | luaE_setdebt(g, stepsize); | ||
1249 | } | ||
1250 | |||
1251 | |||
1252 | /* | ||
1234 | ** Does a young collection. First, mark 'OLD1' objects. Then does the | 1253 | ** Does a young collection. First, mark 'OLD1' objects. Then does the |
1235 | ** atomic step. Then, sweep all lists and advance pointers. Finally, | 1254 | ** atomic step. Then, check whether to continue in minor mode. If so, |
1236 | ** finish the collection. | 1255 | ** sweep all lists and advance pointers. Finally, finish the collection. |
1237 | */ | 1256 | */ |
1238 | static void youngcollection (lua_State *L, global_State *g) { | 1257 | static void youngcollection (lua_State *L, global_State *g) { |
1239 | GCObject **psurvival; /* to point to first non-dead survival object */ | 1258 | GCObject **psurvival; /* to point to first non-dead survival object */ |
1240 | GCObject *dummy; /* dummy out parameter to 'sweepgen' */ | 1259 | GCObject *dummy; /* dummy out parameter to 'sweepgen' */ |
1241 | lua_assert(g->gcstate == GCSpropagate); | 1260 | lua_assert(g->gcstate == GCSpropagate); |
1261 | g->marked = 0; | ||
1242 | if (g->firstold1) { /* are there regular OLD1 objects? */ | 1262 | if (g->firstold1) { /* are there regular OLD1 objects? */ |
1243 | markold(g, g->firstold1, g->reallyold); /* mark them */ | 1263 | markold(g, g->firstold1, g->reallyold); /* mark them */ |
1244 | g->firstold1 = NULL; /* no more OLD1 objects (for now) */ | 1264 | g->firstold1 = NULL; /* no more OLD1 objects (for now) */ |
1245 | } | 1265 | } |
1246 | markold(g, g->finobj, g->finobjrold); | 1266 | markold(g, g->finobj, g->finobjrold); |
1247 | markold(g, g->tobefnz, NULL); | 1267 | markold(g, g->tobefnz, NULL); |
1268 | |||
1248 | atomic(L); | 1269 | atomic(L); |
1249 | 1270 | ||
1271 | /* decide whether to shift to major mode */ | ||
1272 | if (g->GCmajorminor <= 0) { /* ?? */ | ||
1273 | atomic2major(L, g); /* go to major mode */ | ||
1274 | return; /* nothing else to be done here */ | ||
1275 | } | ||
1276 | |||
1250 | /* sweep nursery and get a pointer to its last live element */ | 1277 | /* sweep nursery and get a pointer to its last live element */ |
1251 | g->gcstate = GCSswpallgc; | 1278 | g->gcstate = GCSswpallgc; |
1252 | psurvival = sweepgen(L, g, &g->allgc, g->survival, &g->firstold1); | 1279 | psurvival = sweepgen(L, g, &g->allgc, g->survival, &g->firstold1); |
@@ -1291,8 +1318,8 @@ static void atomic2gen (lua_State *L, global_State *g) { | |||
1291 | 1318 | ||
1292 | sweep2old(L, &g->tobefnz); | 1319 | sweep2old(L, &g->tobefnz); |
1293 | 1320 | ||
1294 | g->gckind = KGC_GEN; | 1321 | g->gckind = KGC_GENMINOR; |
1295 | g->GClastmajor = gettotalobjs(g); /* base for memory control */ | 1322 | g->GCmajorminor = applygcparam(g, genmajormul, g->marked); |
1296 | finishgencycle(L, g); | 1323 | finishgencycle(L, g); |
1297 | } | 1324 | } |
1298 | 1325 | ||
@@ -1328,9 +1355,9 @@ static void entergen (lua_State *L, global_State *g) { | |||
1328 | */ | 1355 | */ |
1329 | static void enterinc (global_State *g) { | 1356 | static void enterinc (global_State *g) { |
1330 | whitelist(g, g->allgc); | 1357 | whitelist(g, g->allgc); |
1331 | g->reallyold = g->old1 = g->survival = NULL; | ||
1332 | whitelist(g, g->finobj); | 1358 | whitelist(g, g->finobj); |
1333 | whitelist(g, g->tobefnz); | 1359 | whitelist(g, g->tobefnz); |
1360 | g->reallyold = g->old1 = g->survival = NULL; | ||
1334 | g->finobjrold = g->finobjold1 = g->finobjsur = NULL; | 1361 | g->finobjrold = g->finobjold1 = g->finobjsur = NULL; |
1335 | g->gcstate = GCSpause; | 1362 | g->gcstate = GCSpause; |
1336 | g->gckind = KGC_INC; | 1363 | g->gckind = KGC_INC; |
@@ -1350,7 +1377,7 @@ void luaC_changemode (lua_State *L, int newmode) { | |||
1350 | enterinc(g); /* entering incremental mode */ | 1377 | enterinc(g); /* entering incremental mode */ |
1351 | } | 1378 | } |
1352 | else { | 1379 | else { |
1353 | lua_assert(newmode == KGC_GEN); | 1380 | lua_assert(newmode == KGC_GENMINOR); |
1354 | entergen(L, g); | 1381 | entergen(L, g); |
1355 | } | 1382 | } |
1356 | } | 1383 | } |
@@ -1367,50 +1394,19 @@ static void fullgen (lua_State *L, global_State *g) { | |||
1367 | 1394 | ||
1368 | 1395 | ||
1369 | /* | 1396 | /* |
1370 | ** Does a major collector up to the atomic phase and then either | 1397 | ** After an atomic incremental step from a major collection, |
1371 | ** returns to minor collections or stays doing major ones. If the | 1398 | ** check whether collector could return to minor collections. |
1372 | ** number of objects collected this time (numobjs - marked) is more than | ||
1373 | ** half the number of objects created since the last major collection | ||
1374 | ** (numobjs - lastmajor), it goes back to minor collections. | ||
1375 | */ | 1399 | */ |
1376 | static void genmajorstep (lua_State *L, global_State *g) { | 1400 | static int checkmajorminor (lua_State *L, global_State *g) { |
1377 | l_obj lastmajor = g->GClastmajor; /* count from last collection */ | 1401 | if (g->gckind == KGC_GENMAJOR) { |
1378 | l_obj numobjs = gettotalobjs(g); /* current count */ | 1402 | l_obj numobjs = gettotalobjs(g); /* current count */ |
1379 | luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ | 1403 | if (g->marked < numobjs - (numobjs >> 2)) { /* ?? */ |
1380 | atomic(L); /* mark everybody */ | 1404 | atomic2gen(L, g); /* return to generational mode */ |
1381 | if ((numobjs - g->marked) > ((numobjs - lastmajor) >> 1)) { | 1405 | setminordebt(g); |
1382 | atomic2gen(L, g); /* return to generational mode */ | 1406 | return 0; /* exit incremental collection */ |
1383 | setminordebt(g); | 1407 | } |
1384 | } | ||
1385 | else { /* bad collection; stay in major mode */ | ||
1386 | entersweep(L); | ||
1387 | luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ | ||
1388 | setpause(g); | ||
1389 | g->GClastmajor = gettotalobjs(g); | ||
1390 | } | ||
1391 | } | ||
1392 | |||
1393 | |||
1394 | /* | ||
1395 | ** Does a generational "step". If the total number of objects grew | ||
1396 | ** more than 'majormul'% since the last major collection, does a | ||
1397 | ** major collection. Otherwise, does a minor collection. | ||
1398 | */ | ||
1399 | static void genstep (lua_State *L, global_State *g) { | ||
1400 | l_obj majorbase = g->GClastmajor; /* count after last major collection */ | ||
1401 | l_obj majorinc = applygcparam(g, genmajormul, majorbase); | ||
1402 | if (gettotalobjs(g) > majorbase + majorinc) { | ||
1403 | /* do a major collection */ | ||
1404 | enterinc(g); | ||
1405 | g->gckind = KGC_GENMAJOR; | ||
1406 | genmajorstep(L, g); | ||
1407 | } | ||
1408 | else { /* regular case; do a minor collection */ | ||
1409 | g->marked = 0; | ||
1410 | youngcollection(L, g); | ||
1411 | setminordebt(g); | ||
1412 | lua_assert(g->GClastmajor == majorbase); | ||
1413 | } | 1408 | } |
1409 | return 1; /* stay doing incremental collections */ | ||
1414 | } | 1410 | } |
1415 | 1411 | ||
1416 | /* }====================================================== */ | 1412 | /* }====================================================== */ |
@@ -1548,7 +1544,8 @@ static l_obj singlestep (lua_State *L) { | |||
1548 | } | 1544 | } |
1549 | case GCSenteratomic: { | 1545 | case GCSenteratomic: { |
1550 | work = atomic(L); | 1546 | work = atomic(L); |
1551 | entersweep(L); | 1547 | if (checkmajorminor(L, g)) |
1548 | entersweep(L); | ||
1552 | break; | 1549 | break; |
1553 | } | 1550 | } |
1554 | case GCSswpallgc: { /* sweep "regular" objects */ | 1551 | case GCSswpallgc: { /* sweep "regular" objects */ |
@@ -1597,6 +1594,7 @@ static l_obj singlestep (lua_State *L) { | |||
1597 | */ | 1594 | */ |
1598 | void luaC_runtilstate (lua_State *L, int statesmask) { | 1595 | void luaC_runtilstate (lua_State *L, int statesmask) { |
1599 | global_State *g = G(L); | 1596 | global_State *g = G(L); |
1597 | lua_assert(g->gckind == KGC_INC); | ||
1600 | while (!testbit(statesmask, g->gcstate)) | 1598 | while (!testbit(statesmask, g->gcstate)) |
1601 | singlestep(L); | 1599 | singlestep(L); |
1602 | } | 1600 | } |
@@ -1615,13 +1613,14 @@ static void incstep (lua_State *L, global_State *g) { | |||
1615 | l_obj work2do = applygcparam(g, gcstepmul, stepsize); | 1613 | l_obj work2do = applygcparam(g, gcstepmul, stepsize); |
1616 | do { /* repeat until pause or enough "credit" (negative debt) */ | 1614 | do { /* repeat until pause or enough "credit" (negative debt) */ |
1617 | l_obj work = singlestep(L); /* perform one single step */ | 1615 | l_obj work = singlestep(L); /* perform one single step */ |
1616 | if (g->gckind == KGC_GENMINOR) /* returned to minor collections? */ | ||
1617 | return; /* nothing else to be done here */ | ||
1618 | work2do -= work; | 1618 | work2do -= work; |
1619 | } while (work2do > 0 && g->gcstate != GCSpause); | 1619 | } while (work2do > 0 && g->gcstate != GCSpause); |
1620 | if (g->gcstate == GCSpause) | 1620 | if (g->gcstate == GCSpause) |
1621 | setpause(g); /* pause until next cycle */ | 1621 | setpause(g); /* pause until next cycle */ |
1622 | else { | 1622 | else |
1623 | luaE_setdebt(g, stepsize); | 1623 | luaE_setdebt(g, stepsize); |
1624 | } | ||
1625 | } | 1624 | } |
1626 | 1625 | ||
1627 | /* | 1626 | /* |
@@ -1635,17 +1634,18 @@ void luaC_step (lua_State *L) { | |||
1635 | if (!gcrunning(g)) /* not running? */ | 1634 | if (!gcrunning(g)) /* not running? */ |
1636 | luaE_setdebt(g, 2000); | 1635 | luaE_setdebt(g, 2000); |
1637 | else { | 1636 | else { |
1637 | //printf("> step: %d %d %ld %ld -> ", g->gckind, g->gcstate, gettotalobjs(g), g->GCdebt); | ||
1638 | |||
1638 | switch (g->gckind) { | 1639 | switch (g->gckind) { |
1639 | case KGC_INC: | 1640 | case KGC_INC: case KGC_GENMAJOR: |
1640 | incstep(L, g); | 1641 | incstep(L, g); |
1641 | break; | 1642 | break; |
1642 | case KGC_GEN: | 1643 | case KGC_GENMINOR: |
1643 | genstep(L, g); | 1644 | youngcollection(L, g); |
1644 | break; | 1645 | setminordebt(g); |
1645 | case KGC_GENMAJOR: | ||
1646 | genmajorstep(L, g); | ||
1647 | break; | 1646 | break; |
1648 | } | 1647 | } |
1648 | //printf("%d %d %ld %ld\n", g->gckind, g->gcstate, gettotalobjs(g), g->GCdebt); | ||
1649 | } | 1649 | } |
1650 | } | 1650 | } |
1651 | 1651 | ||
@@ -1681,10 +1681,15 @@ void luaC_fullgc (lua_State *L, int isemergency) { | |||
1681 | global_State *g = G(L); | 1681 | global_State *g = G(L); |
1682 | lua_assert(!g->gcemergency); | 1682 | lua_assert(!g->gcemergency); |
1683 | g->gcemergency = isemergency; /* set flag */ | 1683 | g->gcemergency = isemergency; /* set flag */ |
1684 | if (g->gckind == KGC_GEN) | 1684 | switch (g->gckind) { |
1685 | fullgen(L, g); | 1685 | case KGC_GENMINOR: fullgen(L, g); break; |
1686 | else | 1686 | case KGC_INC: fullinc(L, g); break; |
1687 | fullinc(L, g); | 1687 | case KGC_GENMAJOR: |
1688 | g->gckind = KGC_INC; | ||
1689 | fullinc(L, g); | ||
1690 | g->gckind = KGC_GENMAJOR; | ||
1691 | break; | ||
1692 | } | ||
1688 | g->gcemergency = 0; | 1693 | g->gcemergency = 0; |
1689 | } | 1694 | } |
1690 | 1695 | ||