diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2022-11-29 10:37:08 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2022-11-29 10:37:08 -0300 |
| commit | d324a0ccf9e2511baf182dd981a8ee9835cee925 (patch) | |
| tree | 7cb36618c0cbafb4a0216a117fd25a78250991a5 | |
| parent | 152b51955aabb9dfb32302569fac810e999eda03 (diff) | |
| download | lua-d324a0ccf9e2511baf182dd981a8ee9835cee925.tar.gz lua-d324a0ccf9e2511baf182dd981a8ee9835cee925.tar.bz2 lua-d324a0ccf9e2511baf182dd981a8ee9835cee925.zip | |
Simpler control for major collections
| -rw-r--r-- | lapi.c | 4 | ||||
| -rw-r--r-- | lgc.c | 190 | ||||
| -rw-r--r-- | lgc.h | 8 | ||||
| -rw-r--r-- | lstate.c | 1 | ||||
| -rw-r--r-- | lstate.h | 8 | ||||
| -rw-r--r-- | ltests.c | 2 |
6 files changed, 77 insertions, 136 deletions
| @@ -1199,7 +1199,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { | |||
| 1199 | case LUA_GCGEN: { | 1199 | case LUA_GCGEN: { |
| 1200 | int minormul = va_arg(argp, int); | 1200 | int minormul = va_arg(argp, int); |
| 1201 | int majormul = va_arg(argp, int); | 1201 | int majormul = va_arg(argp, int); |
| 1202 | res = isdecGCmodegen(g) ? LUA_GCGEN : LUA_GCINC; | 1202 | res = (g->gckind == KGC_INC) ? LUA_GCINC : LUA_GCGEN; |
| 1203 | if (minormul != 0) | 1203 | if (minormul != 0) |
| 1204 | g->genminormul = minormul; | 1204 | g->genminormul = minormul; |
| 1205 | if (majormul != 0) | 1205 | if (majormul != 0) |
| @@ -1211,7 +1211,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { | |||
| 1211 | int pause = va_arg(argp, int); | 1211 | int pause = va_arg(argp, int); |
| 1212 | int stepmul = va_arg(argp, int); | 1212 | int stepmul = va_arg(argp, int); |
| 1213 | int stepsize = va_arg(argp, int); | 1213 | int stepsize = va_arg(argp, int); |
| 1214 | res = isdecGCmodegen(g) ? LUA_GCGEN : LUA_GCINC; | 1214 | res = (g->gckind == KGC_INC) ? LUA_GCINC : LUA_GCGEN; |
| 1215 | if (pause != 0) | 1215 | if (pause != 0) |
| 1216 | setgcparam(g->gcpause, pause); | 1216 | setgcparam(g->gcpause, pause); |
| 1217 | if (stepmul != 0) | 1217 | if (stepmul != 0) |
| @@ -29,23 +29,18 @@ | |||
| 29 | 29 | ||
| 30 | 30 | ||
| 31 | /* | 31 | /* |
| 32 | ** Maximum number of elements to sweep in each single step. | 32 | ** Number of fixed (luaC_fix) objects in a Lua state: metafield names, |
| 33 | ** (Large enough to dissipate fixed overheads but small enough | 33 | ** plus reserved words, plus "_ENV", plus the memory-error message. |
| 34 | ** to allow small steps for the collector.) | ||
| 35 | */ | 34 | */ |
| 36 | #define GCSWEEPMAX 20 | 35 | #define NFIXED (TM_N + NUM_RESERVED + 2) |
| 37 | |||
| 38 | /* | ||
| 39 | ** Maximum number of finalizers to call in each single step. | ||
| 40 | */ | ||
| 41 | #define GCFINMAX 10 | ||
| 42 | 36 | ||
| 43 | 37 | ||
| 44 | /* | 38 | /* |
| 45 | ** Cost of calling one finalizer. | 39 | ** Maximum number of elements to sweep in each single step. |
| 40 | ** (Large enough to dissipate fixed overheads but small enough | ||
| 41 | ** to allow small steps for the collector.) | ||
| 46 | */ | 42 | */ |
| 47 | #define GCFINALIZECOST 50 | 43 | #define GCSWEEPMAX 20 |
| 48 | |||
| 49 | 44 | ||
| 50 | 45 | ||
| 51 | /* mask with all color bits */ | 46 | /* mask with all color bits */ |
| @@ -205,7 +200,7 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { | |||
| 205 | } | 200 | } |
| 206 | else { /* sweep phase */ | 201 | else { /* sweep phase */ |
| 207 | lua_assert(issweepphase(g)); | 202 | lua_assert(issweepphase(g)); |
| 208 | if (g->gckind == KGC_INC) /* incremental mode? */ | 203 | if (g->gckind != KGC_GEN) /* incremental mode? */ |
| 209 | makewhite(g, o); /* mark 'o' as white to avoid other barriers */ | 204 | makewhite(g, o); /* mark 'o' as white to avoid other barriers */ |
| 210 | } | 205 | } |
| 211 | } | 206 | } |
| @@ -398,7 +393,7 @@ static void cleargraylists (global_State *g) { | |||
| 398 | */ | 393 | */ |
| 399 | static void restartcollection (global_State *g) { | 394 | static void restartcollection (global_State *g) { |
| 400 | cleargraylists(g); | 395 | cleargraylists(g); |
| 401 | g->marked = TM_N + NUM_RESERVED + 2; | 396 | g->marked = NFIXED; |
| 402 | markobject(g, g->mainthread); | 397 | markobject(g, g->mainthread); |
| 403 | markvalue(g, &g->l_registry); | 398 | markvalue(g, &g->l_registry); |
| 404 | markmt(g); | 399 | markmt(g); |
| @@ -927,17 +922,6 @@ static void GCTM (lua_State *L) { | |||
| 927 | 922 | ||
| 928 | 923 | ||
| 929 | /* | 924 | /* |
| 930 | ** Call a few finalizers | ||
| 931 | */ | ||
| 932 | static void runafewfinalizers (lua_State *L, int n) { | ||
| 933 | global_State *g = G(L); | ||
| 934 | int i; | ||
| 935 | for (i = 0; i < n && g->tobefnz; i++) | ||
| 936 | GCTM(L); /* call one finalizer */ | ||
| 937 | } | ||
| 938 | |||
| 939 | |||
| 940 | /* | ||
| 941 | ** call all pending finalizers | 925 | ** call all pending finalizers |
| 942 | */ | 926 | */ |
| 943 | static void callallpendingfinalizers (lua_State *L) { | 927 | static void callallpendingfinalizers (lua_State *L) { |
| @@ -1295,8 +1279,7 @@ static void atomic2gen (lua_State *L, global_State *g) { | |||
| 1295 | sweep2old(L, &g->tobefnz); | 1279 | sweep2old(L, &g->tobefnz); |
| 1296 | 1280 | ||
| 1297 | g->gckind = KGC_GEN; | 1281 | g->gckind = KGC_GEN; |
| 1298 | g->lastatomic = 0; | 1282 | g->GClastmajor = gettotalobjs(g); /* base for memory control */ |
| 1299 | g->GCestimate = gettotalobjs(g); /* base for memory control */ | ||
| 1300 | finishgencycle(L, g); | 1283 | finishgencycle(L, g); |
| 1301 | } | 1284 | } |
| 1302 | 1285 | ||
| @@ -1306,7 +1289,7 @@ static void atomic2gen (lua_State *L, global_State *g) { | |||
| 1306 | ** total number of objects grows 'genminormul'%. | 1289 | ** total number of objects grows 'genminormul'%. |
| 1307 | */ | 1290 | */ |
| 1308 | static void setminordebt (global_State *g) { | 1291 | static void setminordebt (global_State *g) { |
| 1309 | luaE_setdebt(g, -(cast(l_obj, (gettotalobjs(g) / 100)) * g->genminormul)); | 1292 | luaE_setdebt(g, -(gettotalobjs(g) / 100) * g->genminormul); |
| 1310 | } | 1293 | } |
| 1311 | 1294 | ||
| 1312 | 1295 | ||
| @@ -1338,7 +1321,6 @@ static void enterinc (global_State *g) { | |||
| 1338 | g->finobjrold = g->finobjold1 = g->finobjsur = NULL; | 1321 | g->finobjrold = g->finobjold1 = g->finobjsur = NULL; |
| 1339 | g->gcstate = GCSpause; | 1322 | g->gcstate = GCSpause; |
| 1340 | g->gckind = KGC_INC; | 1323 | g->gckind = KGC_INC; |
| 1341 | g->lastatomic = 0; | ||
| 1342 | } | 1324 | } |
| 1343 | 1325 | ||
| 1344 | 1326 | ||
| @@ -1347,13 +1329,18 @@ static void enterinc (global_State *g) { | |||
| 1347 | */ | 1329 | */ |
| 1348 | void luaC_changemode (lua_State *L, int newmode) { | 1330 | void luaC_changemode (lua_State *L, int newmode) { |
| 1349 | global_State *g = G(L); | 1331 | global_State *g = G(L); |
| 1350 | if (newmode != g->gckind) { | 1332 | if (newmode != g->gckind) { /* does it need to change? */ |
| 1351 | if (newmode == KGC_GEN) /* entering generational mode? */ | 1333 | if (newmode == KGC_INC) { /* entering incremental mode? */ |
| 1334 | if (g->gckind == KGC_GENMAJOR) | ||
| 1335 | g->gckind = KGC_INC; /* already incremental but in name */ | ||
| 1336 | else | ||
| 1337 | enterinc(g); /* entering incremental mode */ | ||
| 1338 | } | ||
| 1339 | else { | ||
| 1340 | lua_assert(newmode == KGC_GEN); | ||
| 1352 | entergen(L, g); | 1341 | entergen(L, g); |
| 1353 | else | 1342 | } |
| 1354 | enterinc(g); /* entering incremental mode */ | ||
| 1355 | } | 1343 | } |
| 1356 | g->lastatomic = 0; | ||
| 1357 | } | 1344 | } |
| 1358 | 1345 | ||
| 1359 | 1346 | ||
| @@ -1367,93 +1354,52 @@ static void fullgen (lua_State *L, global_State *g) { | |||
| 1367 | 1354 | ||
| 1368 | 1355 | ||
| 1369 | /* | 1356 | /* |
| 1370 | ** Does a major collection after last collection was a "bad collection". | 1357 | ** Does a major collector up to the atomic phase and then either |
| 1371 | ** | 1358 | ** returns to minor collections or stays doing major ones. If the |
| 1372 | ** When the program is building a big structure, it allocates lots of | 1359 | ** number of objects collected this time (numobjs - marked) is more than |
| 1373 | ** memory but generates very little garbage. In those scenarios, | 1360 | ** half the number of objects created since the last major collection |
| 1374 | ** the generational mode just wastes time doing small collections, and | 1361 | ** (numobjs - lastmajor), it goes back to minor collections. |
| 1375 | ** major collections are frequently what we call a "bad collection", a | 1362 | */ |
| 1376 | ** collection that frees too few objects. To avoid the cost of switching | 1363 | static void genmajorstep (lua_State *L, global_State *g) { |
| 1377 | ** between generational mode and the incremental mode needed for full | 1364 | l_obj lastmajor = g->GClastmajor; /* count from last collection */ |
| 1378 | ** (major) collections, the collector tries to stay in incremental mode | 1365 | l_obj numobjs = gettotalobjs(g); /* current count */ |
| 1379 | ** after a bad collection, and to switch back to generational mode only | ||
| 1380 | ** after a "good" collection (one that traverses less than 9/8 objects | ||
| 1381 | ** of the previous one). | ||
| 1382 | ** The collector must choose whether to stay in incremental mode or to | ||
| 1383 | ** switch back to generational mode before sweeping. At this point, it | ||
| 1384 | ** does not know the real memory in use, so it cannot use memory to | ||
| 1385 | ** decide whether to return to generational mode. Instead, it uses the | ||
| 1386 | ** number of objects traversed (returned by 'atomic') as a proxy. The | ||
| 1387 | ** field 'g->lastatomic' keeps this count from the last collection. | ||
| 1388 | ** ('g->lastatomic != 0' also means that the last collection was bad.) | ||
| 1389 | */ | ||
| 1390 | static void stepgenfull (lua_State *L, global_State *g) { | ||
| 1391 | lu_mem lastatomic = g->lastatomic; /* count from last collection */ | ||
| 1392 | if (g->gckind == KGC_GEN) /* still in generational mode? */ | ||
| 1393 | enterinc(g); /* enter incremental mode */ | ||
| 1394 | luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ | 1366 | luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ |
| 1395 | g->marked = 0; | ||
| 1396 | atomic(L); /* mark everybody */ | 1367 | atomic(L); /* mark everybody */ |
| 1397 | if (g->marked < lastatomic + (lastatomic >> 3)) { /* good collection? */ | 1368 | if ((numobjs - g->marked) > ((numobjs - lastmajor) >> 1)) { |
| 1398 | atomic2gen(L, g); /* return to generational mode */ | 1369 | atomic2gen(L, g); /* return to generational mode */ |
| 1399 | setminordebt(g); | 1370 | setminordebt(g); |
| 1400 | } | 1371 | } |
| 1401 | else { /* another bad collection; stay in incremental mode */ | 1372 | else { /* bad collection; stay in major mode */ |
| 1402 | g->GCestimate = gettotalobjs(g); /* first estimate */; | ||
| 1403 | g->lastatomic = g->marked; | ||
| 1404 | entersweep(L); | 1373 | entersweep(L); |
| 1405 | luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ | 1374 | luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ |
| 1406 | setpause(g); | 1375 | setpause(g); |
| 1376 | g->GClastmajor = gettotalobjs(g); | ||
| 1407 | } | 1377 | } |
| 1408 | } | 1378 | } |
| 1409 | 1379 | ||
| 1410 | 1380 | ||
| 1411 | /* | 1381 | /* |
| 1412 | ** Does a generational "step". | 1382 | ** Does a generational "step". If the total number of objects grew |
| 1413 | ** Usually, this means doing a minor collection and setting the debt to | 1383 | ** more than 'majormul'% since the last major collection, does a |
| 1414 | ** make another collection when memory grows 'genminormul'% larger. | 1384 | ** major collection. Otherwise, does a minor collection. The test |
| 1415 | ** | 1385 | ** ('GCdebt' > 0) avoids major collections when the step originated from |
| 1416 | ** However, there are exceptions. If memory grows 'genmajormul'% | 1386 | ** 'collectgarbage("step")'. |
| 1417 | ** larger than it was at the end of the last major collection (kept | ||
| 1418 | ** in 'g->GCestimate'), the function does a major collection. At the | ||
| 1419 | ** end, it checks whether the major collection was able to free a | ||
| 1420 | ** decent amount of memory (at least half the growth in memory since | ||
| 1421 | ** previous major collection). If so, the collector keeps its state, | ||
| 1422 | ** and the next collection will probably be minor again. Otherwise, | ||
| 1423 | ** we have what we call a "bad collection". In that case, set the field | ||
| 1424 | ** 'g->lastatomic' to signal that fact, so that the next collection will | ||
| 1425 | ** go to 'stepgenfull'. | ||
| 1426 | ** | ||
| 1427 | ** 'GCdebt <= 0' means an explicit call to GC step with "size" zero; | ||
| 1428 | ** in that case, do a minor collection. | ||
| 1429 | */ | 1387 | */ |
| 1430 | static void genstep (lua_State *L, global_State *g) { | 1388 | static void genstep (lua_State *L, global_State *g) { |
| 1431 | if (g->lastatomic != 0) /* last collection was a bad one? */ | 1389 | l_obj majorbase = g->GClastmajor; /* count after last major collection */ |
| 1432 | stepgenfull(L, g); /* do a full step */ | 1390 | l_obj majorinc = (majorbase / 100) * getgcparam(g->genmajormul); |
| 1433 | else { | 1391 | if (g->GCdebt > 0 && gettotalobjs(g) > majorbase + majorinc) { |
| 1434 | l_obj majorbase = g->GCestimate; /* objects after last major collection */ | 1392 | /* do a major collection */ |
| 1435 | l_obj majorinc = (majorbase / 100) * getgcparam(g->genmajormul); | 1393 | enterinc(g); |
| 1436 | if (g->GCdebt > 0 && gettotalobjs(g) > majorbase + majorinc) { | 1394 | g->gckind = KGC_GENMAJOR; |
| 1437 | g->marked = 0; | 1395 | genmajorstep(L, g); |
| 1438 | fullgen(L, g); /* do a major collection */ | 1396 | } |
| 1439 | if (gettotalobjs(g) < majorbase + (majorinc / 2)) { | 1397 | else { /* regular case; do a minor collection */ |
| 1440 | /* collected at least half of object growth since last major | 1398 | g->marked = 0; |
| 1441 | collection; keep doing minor collections. */ | 1399 | youngcollection(L, g); |
| 1442 | lua_assert(g->lastatomic == 0); | 1400 | setminordebt(g); |
| 1443 | } | 1401 | lua_assert(g->GClastmajor == majorbase); |
| 1444 | else { /* bad collection */ | ||
| 1445 | g->lastatomic = g->marked; /* signal that last collection was bad */ | ||
| 1446 | setpause(g); /* do a long wait for next (major) collection */ | ||
| 1447 | } | ||
| 1448 | } | ||
| 1449 | else { /* regular case; do a minor collection */ | ||
| 1450 | g->marked = 0; | ||
| 1451 | youngcollection(L, g); | ||
| 1452 | setminordebt(g); | ||
| 1453 | g->GCestimate = majorbase; /* preserve base value */ | ||
| 1454 | } | ||
| 1455 | } | 1402 | } |
| 1456 | lua_assert(isdecGCmodegen(g)); | ||
| 1457 | } | 1403 | } |
| 1458 | 1404 | ||
| 1459 | /* }====================================================== */ | 1405 | /* }====================================================== */ |
| @@ -1557,11 +1503,8 @@ static l_obj atomic (lua_State *L) { | |||
| 1557 | 1503 | ||
| 1558 | static void sweepstep (lua_State *L, global_State *g, | 1504 | static void sweepstep (lua_State *L, global_State *g, |
| 1559 | int nextstate, GCObject **nextlist) { | 1505 | int nextstate, GCObject **nextlist) { |
| 1560 | if (g->sweepgc) { | 1506 | if (g->sweepgc) |
| 1561 | l_obj olddebt = g->GCdebt; | ||
| 1562 | g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); | 1507 | g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); |
| 1563 | g->GCestimate += g->GCdebt - olddebt; /* update estimate */ | ||
| 1564 | } | ||
| 1565 | else { /* enter next state */ | 1508 | else { /* enter next state */ |
| 1566 | g->gcstate = nextstate; | 1509 | g->gcstate = nextstate; |
| 1567 | g->sweepgc = nextlist; | 1510 | g->sweepgc = nextlist; |
| @@ -1618,11 +1561,11 @@ static l_obj singlestep (lua_State *L) { | |||
| 1618 | work = 0; | 1561 | work = 0; |
| 1619 | break; | 1562 | break; |
| 1620 | } | 1563 | } |
| 1621 | case GCScallfin: { /* call remaining finalizers */ | 1564 | case GCScallfin: { /* call finalizers */ |
| 1622 | if (g->tobefnz && !g->gcemergency) { | 1565 | if (g->tobefnz && !g->gcemergency) { |
| 1623 | g->gcstopem = 0; /* ok collections during finalizers */ | 1566 | g->gcstopem = 0; /* ok collections during finalizers */ |
| 1624 | runafewfinalizers(L, GCFINMAX); | 1567 | GCTM(L); /* call one finalizer */ |
| 1625 | work = GCFINMAX * GCFINALIZECOST; | 1568 | work = 1; |
| 1626 | } | 1569 | } |
| 1627 | else { /* emergency mode or no more finalizers */ | 1570 | else { /* emergency mode or no more finalizers */ |
| 1628 | g->gcstate = GCSpause; /* finish collection */ | 1571 | g->gcstate = GCSpause; /* finish collection */ |
| @@ -1679,10 +1622,17 @@ void luaC_step (lua_State *L) { | |||
| 1679 | global_State *g = G(L); | 1622 | global_State *g = G(L); |
| 1680 | lua_assert(!g->gcemergency); | 1623 | lua_assert(!g->gcemergency); |
| 1681 | if (gcrunning(g)) { /* running? */ | 1624 | if (gcrunning(g)) { /* running? */ |
| 1682 | if(isdecGCmodegen(g)) | 1625 | switch (g->gckind) { |
| 1683 | genstep(L, g); | 1626 | case KGC_INC: |
| 1684 | else | 1627 | incstep(L, g); |
| 1685 | incstep(L, g); | 1628 | break; |
| 1629 | case KGC_GEN: | ||
| 1630 | genstep(L, g); | ||
| 1631 | break; | ||
| 1632 | case KGC_GENMAJOR: | ||
| 1633 | genmajorstep(L, g); | ||
| 1634 | break; | ||
| 1635 | } | ||
| 1686 | } | 1636 | } |
| 1687 | } | 1637 | } |
| 1688 | 1638 | ||
| @@ -1700,7 +1650,7 @@ static void fullinc (lua_State *L, global_State *g) { | |||
| 1700 | /* finish any pending sweep phase to start a new cycle */ | 1650 | /* finish any pending sweep phase to start a new cycle */ |
| 1701 | luaC_runtilstate(L, bitmask(GCSpause)); | 1651 | luaC_runtilstate(L, bitmask(GCSpause)); |
| 1702 | luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ | 1652 | luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ |
| 1703 | /* estimate must be correct after a full GC cycle */ | 1653 | /* 'marked' must be correct after a full GC cycle */ |
| 1704 | lua_assert(g->marked == gettotalobjs(g)); | 1654 | lua_assert(g->marked == gettotalobjs(g)); |
| 1705 | luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ | 1655 | luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ |
| 1706 | setpause(g); | 1656 | setpause(g); |
| @@ -1716,10 +1666,10 @@ void luaC_fullgc (lua_State *L, int isemergency) { | |||
| 1716 | global_State *g = G(L); | 1666 | global_State *g = G(L); |
| 1717 | lua_assert(!g->gcemergency); | 1667 | lua_assert(!g->gcemergency); |
| 1718 | g->gcemergency = isemergency; /* set flag */ | 1668 | g->gcemergency = isemergency; /* set flag */ |
| 1719 | if (g->gckind == KGC_INC) | 1669 | if (g->gckind == KGC_GEN) |
| 1720 | fullinc(L, g); | ||
| 1721 | else | ||
| 1722 | fullgen(L, g); | 1670 | fullgen(L, g); |
| 1671 | else | ||
| 1672 | fullinc(L, g); | ||
| 1723 | g->gcemergency = 0; | 1673 | g->gcemergency = 0; |
| 1724 | } | 1674 | } |
| 1725 | 1675 | ||
| @@ -142,14 +142,6 @@ | |||
| 142 | 142 | ||
| 143 | 143 | ||
| 144 | /* | 144 | /* |
| 145 | ** Check whether the declared GC mode is generational. While in | ||
| 146 | ** generational mode, the collector can go temporarily to incremental | ||
| 147 | ** mode to improve performance. This is signaled by 'g->lastatomic != 0'. | ||
| 148 | */ | ||
| 149 | #define isdecGCmodegen(g) (g->gckind == KGC_GEN || g->lastatomic != 0) | ||
| 150 | |||
| 151 | |||
| 152 | /* | ||
| 153 | ** Control when GC is running: | 145 | ** Control when GC is running: |
| 154 | */ | 146 | */ |
| 155 | #define GCSTPUSR 1 /* bit true when GC stopped by user */ | 147 | #define GCSTPUSR 1 /* bit true when GC stopped by user */ |
| @@ -391,7 +391,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | |||
| 391 | g->totalobjs = 1; | 391 | g->totalobjs = 1; |
| 392 | g->marked = 0; | 392 | g->marked = 0; |
| 393 | g->GCdebt = 0; | 393 | g->GCdebt = 0; |
| 394 | g->lastatomic = 0; | ||
| 395 | setivalue(&g->nilvalue, 0); /* to signal that state is not yet built */ | 394 | setivalue(&g->nilvalue, 0); /* to signal that state is not yet built */ |
| 396 | setgcparam(g->gcpause, LUAI_GCPAUSE); | 395 | setgcparam(g->gcpause, LUAI_GCPAUSE); |
| 397 | setgcparam(g->gcstepmul, LUAI_GCMUL); | 396 | setgcparam(g->gcstepmul, LUAI_GCMUL); |
| @@ -145,12 +145,13 @@ struct lua_longjmp; /* defined in ldo.c */ | |||
| 145 | /* kinds of Garbage Collection */ | 145 | /* kinds of Garbage Collection */ |
| 146 | #define KGC_INC 0 /* incremental gc */ | 146 | #define KGC_INC 0 /* incremental gc */ |
| 147 | #define KGC_GEN 1 /* generational gc */ | 147 | #define KGC_GEN 1 /* generational gc */ |
| 148 | #define KGC_GENMAJOR 2 /* generational in "major" mode */ | ||
| 148 | 149 | ||
| 149 | 150 | ||
| 150 | typedef struct stringtable { | 151 | typedef struct stringtable { |
| 151 | TString **hash; | 152 | TString **hash; /* array of buckets (linked lists of strings) */ |
| 152 | int nuse; /* number of elements */ | 153 | int nuse; /* number of elements */ |
| 153 | int size; | 154 | int size; /* number of buckets */ |
| 154 | } stringtable; | 155 | } stringtable; |
| 155 | 156 | ||
| 156 | 157 | ||
| @@ -253,8 +254,7 @@ typedef struct global_State { | |||
| 253 | l_obj totalobjs; /* total number of objects allocated - GCdebt */ | 254 | l_obj totalobjs; /* total number of objects allocated - GCdebt */ |
| 254 | l_obj GCdebt; /* bytes allocated not yet compensated by the collector */ | 255 | l_obj GCdebt; /* bytes allocated not yet compensated by the collector */ |
| 255 | l_obj marked; /* number of objects marked in a GC cycle */ | 256 | l_obj marked; /* number of objects marked in a GC cycle */ |
| 256 | lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ | 257 | l_obj GClastmajor; /* objects at last major collection */ |
| 257 | lu_mem lastatomic; /* see function 'genstep' in file 'lgc.c' */ | ||
| 258 | stringtable strt; /* hash table for strings */ | 258 | stringtable strt; /* hash table for strings */ |
| 259 | TValue l_registry; | 259 | TValue l_registry; |
| 260 | TValue nilvalue; /* a nil value */ | 260 | 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_INC) | 300 | else if (g->gckind != KGC_GEN) |
| 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)) |
