aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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}