aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2020-07-28 15:51:07 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2020-07-28 15:51:07 -0300
commit663f83f647f9199541ce1b60a6496b4124b4fdd3 (patch)
treedda303bc832d520d0c5d6d60f81a8502e6f6dd54
parentae5b5ba529753c7a653901ffc29b5ea24c3fdf3a (diff)
downloadlua-663f83f647f9199541ce1b60a6496b4124b4fdd3.tar.gz
lua-663f83f647f9199541ce1b60a6496b4124b4fdd3.tar.bz2
lua-663f83f647f9199541ce1b60a6496b4124b4fdd3.zip
Same changes around 'correctgraylist'
Instead of adding all tables and userdata back to the 'grayagain' list to be checked by 'correctgraylist', the collector adds only the objects that will remain in that list (objects aged TOUCHED1). This commit also rewrites 'correctgraylist' with a clearer logic.
-rw-r--r--lgc.c119
1 files changed, 66 insertions, 53 deletions
diff --git a/lgc.c b/lgc.c
index 3591c699..faa9c902 100644
--- a/lgc.c
+++ b/lgc.c
@@ -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
406static 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*/
431static int traverseephemeron (global_State *g, Table *h, int inv) { 458static 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*/
1013static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, 1035static 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*/
1066static GCObject **correctgraylist (GCObject **p) { 1089static 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}