diff options
-rw-r--r-- | lgc.c | 119 |
1 files changed, 66 insertions, 53 deletions
@@ -389,6 +389,32 @@ static void restartcollection (global_State *g) { | |||
389 | ** ======================================================= | 389 | ** ======================================================= |
390 | */ | 390 | */ |
391 | 391 | ||
392 | |||
393 | /* | ||
394 | ** Check whether object 'o' should be kept in the 'grayagain' list for | ||
395 | ** post-processing by 'correctgraylist'. (It could put all old objects | ||
396 | ** in the list and leave all the work to 'correctgraylist', but it is | ||
397 | ** more efficient to avoid adding elements that will be removed.) Only | ||
398 | ** TOUCHED1 objects need to be in the list. TOUCHED2 doesn't need to go | ||
399 | ** back to a gray list, but then it must become OLD. (That is what | ||
400 | ** 'correctgraylist' does when it finds a TOUCHED2 object.) | ||
401 | ** It is defined as a macro because 'gclist' is not a unique field in | ||
402 | ** different collectable objects. | ||
403 | */ | ||
404 | #define genlink(g,o) genlink_(g, obj2gco(o), &(o)->gclist) | ||
405 | |||
406 | static void genlink_ (global_State *g, GCObject *o, GCObject **pnext) { | ||
407 | lua_assert(isblack(o)); | ||
408 | if (getage(o) == G_TOUCHED1) { /* touched in this cycle? */ | ||
409 | *pnext = g->grayagain; /* link it back in 'grayagain' */ | ||
410 | g->grayagain = o; | ||
411 | black2gray(o); | ||
412 | } /* everything else do not need to be linked back */ | ||
413 | else if (getage(o) == G_TOUCHED2) | ||
414 | changeage(o, G_TOUCHED2, G_OLD); /* advance age */ | ||
415 | } | ||
416 | |||
417 | |||
392 | /* | 418 | /* |
393 | ** Traverse a table with weak values and link it to proper list. During | 419 | ** Traverse a table with weak values and link it to proper list. During |
394 | ** propagate phase, keep it in 'grayagain' list, to be revisited in the | 420 | ** propagate phase, keep it in 'grayagain' list, to be revisited in the |
@@ -425,8 +451,9 @@ static void traverseweakvalue (global_State *g, Table *h) { | |||
425 | ** the atomic phase, if table has any white->white entry, it has to | 451 | ** the atomic phase, if table has any white->white entry, it has to |
426 | ** be revisited during ephemeron convergence (as that key may turn | 452 | ** be revisited during ephemeron convergence (as that key may turn |
427 | ** black). Otherwise, if it has any white key, table has to be cleared | 453 | ** black). Otherwise, if it has any white key, table has to be cleared |
428 | ** (in the atomic phase). In generational mode, it (like all visited | 454 | ** (in the atomic phase). In generational mode, some tables |
429 | ** tables) must be kept in some gray list for post-processing. | 455 | ** must be kept in some gray list for post-processing; this is done |
456 | ** by 'genlink'. | ||
430 | */ | 457 | */ |
431 | static int traverseephemeron (global_State *g, Table *h, int inv) { | 458 | static int traverseephemeron (global_State *g, Table *h, int inv) { |
432 | int marked = 0; /* true if an object is marked in this traversal */ | 459 | int marked = 0; /* true if an object is marked in this traversal */ |
@@ -465,10 +492,10 @@ static int traverseephemeron (global_State *g, Table *h, int inv) { | |||
465 | linkgclist(h, g->ephemeron); /* have to propagate again */ | 492 | linkgclist(h, g->ephemeron); /* have to propagate again */ |
466 | else if (hasclears) /* table has white keys? */ | 493 | else if (hasclears) /* table has white keys? */ |
467 | linkgclist(h, g->allweak); /* may have to clean white keys */ | 494 | linkgclist(h, g->allweak); /* may have to clean white keys */ |
468 | else if (g->gckind == KGC_GEN) | 495 | else { |
469 | linkgclist(h, g->grayagain); /* keep it in some list */ | 496 | gray2black(h); /* 'genlink' expects black objects */ |
470 | else | 497 | genlink(g, h); /* check whether collector still needs to see it */ |
471 | gray2black(h); | 498 | } |
472 | return marked; | 499 | return marked; |
473 | } | 500 | } |
474 | 501 | ||
@@ -488,10 +515,7 @@ static void traversestrongtable (global_State *g, Table *h) { | |||
488 | markvalue(g, gval(n)); | 515 | markvalue(g, gval(n)); |
489 | } | 516 | } |
490 | } | 517 | } |
491 | if (g->gckind == KGC_GEN) { | 518 | genlink(g, h); |
492 | linkgclist(h, g->grayagain); /* keep it in some gray list */ | ||
493 | black2gray(h); | ||
494 | } | ||
495 | } | 519 | } |
496 | 520 | ||
497 | 521 | ||
@@ -503,7 +527,7 @@ static lu_mem traversetable (global_State *g, Table *h) { | |||
503 | (cast_void(weakkey = strchr(svalue(mode), 'k')), | 527 | (cast_void(weakkey = strchr(svalue(mode), 'k')), |
504 | cast_void(weakvalue = strchr(svalue(mode), 'v')), | 528 | cast_void(weakvalue = strchr(svalue(mode), 'v')), |
505 | (weakkey || weakvalue))) { /* is really weak? */ | 529 | (weakkey || weakvalue))) { /* is really weak? */ |
506 | black2gray(h); /* keep table gray */ | 530 | black2gray(h); /* turn it back to gray, as it probably goes to a list */ |
507 | if (!weakkey) /* strong keys? */ | 531 | if (!weakkey) /* strong keys? */ |
508 | traverseweakvalue(g, h); | 532 | traverseweakvalue(g, h); |
509 | else if (!weakvalue) /* strong values? */ | 533 | else if (!weakvalue) /* strong values? */ |
@@ -522,10 +546,7 @@ static int traverseudata (global_State *g, Udata *u) { | |||
522 | markobjectN(g, u->metatable); /* mark its metatable */ | 546 | markobjectN(g, u->metatable); /* mark its metatable */ |
523 | for (i = 0; i < u->nuvalue; i++) | 547 | for (i = 0; i < u->nuvalue; i++) |
524 | markvalue(g, &u->uv[i].uv); | 548 | markvalue(g, &u->uv[i].uv); |
525 | if (g->gckind == KGC_GEN) { | 549 | genlink(g, u); |
526 | linkgclist(u, g->grayagain); /* keep it in some gray list */ | ||
527 | black2gray(u); | ||
528 | } | ||
529 | return 1 + u->nuvalue; | 550 | return 1 + u->nuvalue; |
530 | } | 551 | } |
531 | 552 | ||
@@ -1006,9 +1027,10 @@ static void sweep2old (lua_State *L, GCObject **p) { | |||
1006 | ** during the sweep. So, any white object must be dead.) For | 1027 | ** during the sweep. So, any white object must be dead.) For |
1007 | ** non-dead objects, advance their ages and clear the color of | 1028 | ** non-dead objects, advance their ages and clear the color of |
1008 | ** new objects. (Old objects keep their colors.) | 1029 | ** new objects. (Old objects keep their colors.) |
1009 | ** The ages of G_TOUCHED1 and G_TOUCHED2 objects will advance | 1030 | ** The ages of G_TOUCHED1 and G_TOUCHED2 objects cannot be advanced |
1010 | ** in 'correctgraylist'. (That function will also remove objects | 1031 | ** here, because these old-generation objects are usually not swept |
1011 | ** turned white here from any gray list.) | 1032 | ** here. They will all be advanced in 'correctgraylist'. That function |
1033 | ** will also remove objects turned white here from any gray list. | ||
1012 | */ | 1034 | */ |
1013 | static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, | 1035 | static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, |
1014 | GCObject *limit) { | 1036 | GCObject *limit) { |
@@ -1056,48 +1078,39 @@ static void whitelist (global_State *g, GCObject *p) { | |||
1056 | 1078 | ||
1057 | 1079 | ||
1058 | /* | 1080 | /* |
1059 | ** Correct a list of gray objects. | 1081 | ** Correct a list of gray objects. Return pointer to where rest of the |
1082 | ** list should be linked. | ||
1060 | ** Because this correction is done after sweeping, young objects might | 1083 | ** Because this correction is done after sweeping, young objects might |
1061 | ** be turned white and still be in the list. They are only removed. | 1084 | ** be turned white and still be in the list. They are only removed. |
1062 | ** For tables and userdata, advance 'touched1' to 'touched2'; 'touched2' | 1085 | ** 'TOUCHED1' objects are advanced to 'TOUCHED2' and remain on the list; |
1063 | ** objects become regular old and are removed from the list. | 1086 | ** Non-white threads also remain on the list; 'TOUCHED2' objects become |
1064 | ** For threads, just remove white ones from the list. | 1087 | ** regular old; they and anything else are removed from the list. |
1065 | */ | 1088 | */ |
1066 | static GCObject **correctgraylist (GCObject **p) { | 1089 | static GCObject **correctgraylist (GCObject **p) { |
1067 | GCObject *curr; | 1090 | GCObject *curr; |
1068 | while ((curr = *p) != NULL) { | 1091 | while ((curr = *p) != NULL) { |
1069 | switch (curr->tt) { | 1092 | GCObject **next = getgclist(curr); |
1070 | case LUA_VTABLE: case LUA_VUSERDATA: { | 1093 | if (iswhite(curr)) |
1071 | GCObject **next = getgclist(curr); | 1094 | goto remove; /* remove all white objects */ |
1072 | if (getage(curr) == G_TOUCHED1) { /* touched in this cycle? */ | 1095 | else if (getage(curr) == G_TOUCHED1) { /* touched in this cycle? */ |
1073 | lua_assert(isgray(curr)); | 1096 | lua_assert(isgray(curr)); |
1074 | gray2black(curr); /* make it black, for next barrier */ | 1097 | gray2black(curr); /* make it black, for next barrier */ |
1075 | changeage(curr, G_TOUCHED1, G_TOUCHED2); | 1098 | changeage(curr, G_TOUCHED1, G_TOUCHED2); |
1076 | p = next; /* keep it in the list and go to next element */ | 1099 | goto remain; /* keep it in the list and go to next element */ |
1077 | } | 1100 | } |
1078 | else { /* everything else is removed */ | 1101 | else if (curr->tt == LUA_VTHREAD) { |
1079 | /* white objects are simply removed */ | 1102 | lua_assert(isgray(curr)); |
1080 | if (!iswhite(curr)) { /* not white? */ | 1103 | goto remain; /* keep non-white threads on the list */ |
1081 | lua_assert(isold(curr)); | 1104 | } |
1082 | if (getage(curr) == G_TOUCHED2) /* advance from G_TOUCHED2... */ | 1105 | else { /* everything else is removed */ |
1083 | changeage(curr, G_TOUCHED2, G_OLD); /* ... to G_OLD */ | 1106 | lua_assert(isold(curr)); /* young objects should be white */ |
1084 | gray2black(curr); /* make it black */ | 1107 | if (getage(curr) == G_TOUCHED2) /* advance from G_TOUCHED2... */ |
1085 | } | 1108 | changeage(curr, G_TOUCHED2, G_OLD); /* ... to G_OLD */ |
1086 | *p = *next; /* remove 'curr' from gray list */ | 1109 | gray2black(curr); /* make object black */ |
1087 | } | 1110 | goto remove; |
1088 | break; | ||
1089 | } | ||
1090 | case LUA_VTHREAD: { | ||
1091 | lua_State *th = gco2th(curr); | ||
1092 | lua_assert(!isblack(th)); | ||
1093 | if (iswhite(th)) /* new object? */ | ||
1094 | *p = th->gclist; /* remove from gray list */ | ||
1095 | else /* old threads remain gray */ | ||
1096 | p = &th->gclist; /* go to next element */ | ||
1097 | break; | ||
1098 | } | ||
1099 | default: lua_assert(0); /* nothing more could be gray here */ | ||
1100 | } | 1111 | } |
1112 | remove: *p = *next; continue; | ||
1113 | remain: p = next; continue; | ||
1101 | } | 1114 | } |
1102 | return p; | 1115 | return p; |
1103 | } | 1116 | } |