diff options
| -rw-r--r-- | lapi.c | 2 | ||||
| -rw-r--r-- | lgc.c | 141 | ||||
| -rw-r--r-- | lstate.h | 6 | ||||
| -rw-r--r-- | ltests.c | 6 |
4 files changed, 80 insertions, 75 deletions
| @@ -1211,7 +1211,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { | |||
| 1211 | setgcparam(g, genminormul, minormul); | 1211 | setgcparam(g, genminormul, minormul); |
| 1212 | if (majormul != 0) | 1212 | if (majormul != 0) |
| 1213 | setgcparam(g, genmajormul, majormul); | 1213 | setgcparam(g, genmajormul, majormul); |
| 1214 | luaC_changemode(L, KGC_GEN); | 1214 | luaC_changemode(L, KGC_GENMINOR); |
| 1215 | break; | 1215 | break; |
| 1216 | } | 1216 | } |
| 1217 | case LUA_GCINC: { | 1217 | case LUA_GCINC: { |
| @@ -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 | ||
| @@ -149,8 +149,8 @@ struct lua_longjmp; /* defined in ldo.c */ | |||
| 149 | 149 | ||
| 150 | /* kinds of Garbage Collection */ | 150 | /* kinds of Garbage Collection */ |
| 151 | #define KGC_INC 0 /* incremental gc */ | 151 | #define KGC_INC 0 /* incremental gc */ |
| 152 | #define KGC_GEN 1 /* generational gc */ | 152 | #define KGC_GENMINOR 1 /* generational gc in minor (regular) mode */ |
| 153 | #define KGC_GENMAJOR 2 /* generational in "major" mode */ | 153 | #define KGC_GENMAJOR 2 /* generational in major mode */ |
| 154 | 154 | ||
| 155 | 155 | ||
| 156 | typedef struct stringtable { | 156 | typedef struct stringtable { |
| @@ -259,7 +259,7 @@ typedef struct global_State { | |||
| 259 | l_obj totalobjs; /* total number of objects allocated + GCdebt */ | 259 | l_obj totalobjs; /* total number of objects allocated + GCdebt */ |
| 260 | l_obj GCdebt; /* objects counted but not yet allocated */ | 260 | l_obj GCdebt; /* objects counted but not yet allocated */ |
| 261 | l_obj marked; /* number of objects marked in a GC cycle */ | 261 | l_obj marked; /* number of objects marked in a GC cycle */ |
| 262 | l_obj GClastmajor; /* objects at last major collection */ | 262 | l_obj GCmajorminor; /* auxiliar counter to control major-minor shifts */ |
| 263 | stringtable strt; /* hash table for strings */ | 263 | stringtable strt; /* hash table for strings */ |
| 264 | TValue l_registry; | 264 | TValue l_registry; |
| 265 | TValue nilvalue; /* a nil value */ | 265 | TValue nilvalue; /* a nil value */ |
| @@ -297,7 +297,7 @@ static int testobjref1 (global_State *g, GCObject *f, GCObject *t) { | |||
| 297 | if (isdead(g,t)) return 0; | 297 | if (isdead(g,t)) return 0; |
| 298 | if (issweepphase(g)) | 298 | if (issweepphase(g)) |
| 299 | return 1; /* no invariants */ | 299 | return 1; /* no invariants */ |
| 300 | else if (g->gckind != KGC_GEN) | 300 | else if (g->gckind != KGC_GENMINOR) |
| 301 | return !(isblack(f) && iswhite(t)); /* basic incremental invariant */ | 301 | return !(isblack(f) && iswhite(t)); /* basic incremental invariant */ |
| 302 | else { /* generational mode */ | 302 | else { /* generational mode */ |
| 303 | if ((getage(f) == G_OLD && isblack(f)) && !isold(t)) | 303 | if ((getage(f) == G_OLD && isblack(f)) && !isold(t)) |
| @@ -519,7 +519,7 @@ static void checkobject (global_State *g, GCObject *o, int maybedead, | |||
| 519 | assert(maybedead); | 519 | assert(maybedead); |
| 520 | else { | 520 | else { |
| 521 | assert(g->gcstate != GCSpause || iswhite(o)); | 521 | assert(g->gcstate != GCSpause || iswhite(o)); |
| 522 | if (g->gckind == KGC_GEN) { /* generational mode? */ | 522 | if (g->gckind == KGC_GENMINOR) { /* generational mode? */ |
| 523 | assert(getage(o) >= listage); | 523 | assert(getage(o) >= listage); |
| 524 | if (isold(o)) { | 524 | if (isold(o)) { |
| 525 | assert(!iswhite(o)); | 525 | assert(!iswhite(o)); |
| @@ -953,7 +953,7 @@ static int gc_state (lua_State *L) { | |||
| 953 | } | 953 | } |
| 954 | else { | 954 | else { |
| 955 | global_State *g = G(L); | 955 | global_State *g = G(L); |
| 956 | if (G(L)->gckind == KGC_GEN) | 956 | if (G(L)->gckind != KGC_INC) |
| 957 | luaL_error(L, "cannot change states in generational mode"); | 957 | luaL_error(L, "cannot change states in generational mode"); |
| 958 | lua_lock(L); | 958 | lua_lock(L); |
| 959 | if (option < g->gcstate) { /* must cross 'pause'? */ | 959 | if (option < g->gcstate) { /* must cross 'pause'? */ |
