aboutsummaryrefslogtreecommitdiff
path: root/lgc.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2017-04-10 10:33:04 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2017-04-10 10:33:04 -0300
commit9569ad6b0ddcde43eb893d2cfe5bcdb715c0ff20 (patch)
tree8b53a4007fb476d59a8f83cbb3f97b0254f93f1b /lgc.c
parent2331e1beec01babf78ca09fea8701b5bb3c78d4c (diff)
downloadlua-9569ad6b0ddcde43eb893d2cfe5bcdb715c0ff20.tar.gz
lua-9569ad6b0ddcde43eb893d2cfe5bcdb715c0ff20.tar.bz2
lua-9569ad6b0ddcde43eb893d2cfe5bcdb715c0ff20.zip
Comments for generational collector
Diffstat (limited to 'lgc.c')
-rw-r--r--lgc.c191
1 files changed, 128 insertions, 63 deletions
diff --git a/lgc.c b/lgc.c
index 73114300..68a7622f 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.c,v 2.216 2017/02/23 21:07:34 roberto Exp roberto $ 2** $Id: lgc.c,v 2.218 2017/04/06 13:08:56 roberto Exp roberto $
3** Garbage Collector 3** Garbage Collector
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -153,8 +153,8 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
153 if (keepinvariant(g)) { /* must keep invariant? */ 153 if (keepinvariant(g)) { /* must keep invariant? */
154 reallymarkobject(g, v); /* restore invariant */ 154 reallymarkobject(g, v); /* restore invariant */
155 if (isold(o)) { 155 if (isold(o)) {
156 lua_assert(!isold(v)); 156 lua_assert(!isold(v)); /* white object could not be old */
157 setage(v, G_OLD0); 157 setage(v, G_OLD0); /* restore generational invariant */
158 } 158 }
159 } 159 }
160 else { /* sweep phase */ 160 else { /* sweep phase */
@@ -171,8 +171,7 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
171void luaC_barrierback_ (lua_State *L, Table *t) { 171void luaC_barrierback_ (lua_State *L, Table *t) {
172 global_State *g = G(L); 172 global_State *g = G(L);
173 lua_assert(isblack(t) && !isdead(g, t)); 173 lua_assert(isblack(t) && !isdead(g, t));
174 lua_assert(issweepphase(g) || getage(t) != G_TOUCHED1); 174 lua_assert(g->gckind != KGC_GEN || (isold(t) && getage(t) != G_TOUCHED1));
175 lua_assert(g->gckind != KGC_GEN || isold(t));
176 if (getage(t) != G_TOUCHED2) /* not already in gray list? */ 175 if (getage(t) != G_TOUCHED2) /* not already in gray list? */
177 linkgclist(t, g->grayagain); /* link it in 'grayagain' */ 176 linkgclist(t, g->grayagain); /* link it in 'grayagain' */
178 black2gray(t); /* make table gray (again) */ 177 black2gray(t); /* make table gray (again) */
@@ -393,7 +392,8 @@ static void traverseweakvalue (global_State *g, Table *h) {
393** the atomic phase, if table has any white->white entry, it has to 392** the atomic phase, if table has any white->white entry, it has to
394** be revisited during ephemeron convergence (as that key may turn 393** be revisited during ephemeron convergence (as that key may turn
395** black). Otherwise, if it has any white key, table has to be cleared 394** black). Otherwise, if it has any white key, table has to be cleared
396** (in the atomic phase). 395** (in the atomic phase). In generational mode, it (like all visited
396** tables) must be kept in some gray list for post-processing.
397*/ 397*/
398static int traverseephemeron (global_State *g, Table *h) { 398static int traverseephemeron (global_State *g, Table *h) {
399 int marked = 0; /* true if an object is marked in this traversal */ 399 int marked = 0; /* true if an object is marked in this traversal */
@@ -524,9 +524,9 @@ static lu_mem traverseCclosure (global_State *g, CClosure *cl) {
524static lu_mem traverseLclosure (global_State *g, LClosure *cl) { 524static lu_mem traverseLclosure (global_State *g, LClosure *cl) {
525 int i; 525 int i;
526 markobjectN(g, cl->p); /* mark its prototype */ 526 markobjectN(g, cl->p); /* mark its prototype */
527 for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */ 527 for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */
528 UpVal *uv = cl->upvals[i]; 528 UpVal *uv = cl->upvals[i];
529 if (uv != NULL) { 529 if (uv != NULL) { /* can be NULL while closure is being built */
530 if (upisopen(uv) && g->gcstate != GCSatomic) 530 if (upisopen(uv) && g->gcstate != GCSatomic)
531 uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */ 531 uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */
532 else 532 else
@@ -683,6 +683,10 @@ static void clearvalues (global_State *g, GCObject *l, GCObject *f) {
683} 683}
684 684
685 685
686/*
687** Decrement the reference count of an upvalue. If it goes to zero and
688** upvalue is closed, delete it.
689*/
686void luaC_upvdeccount (lua_State *L, UpVal *uv) { 690void luaC_upvdeccount (lua_State *L, UpVal *uv) {
687 lua_assert(uv->refcount > 0); 691 lua_assert(uv->refcount > 0);
688 uv->refcount--; 692 uv->refcount--;
@@ -704,26 +708,31 @@ static void freeLclosure (lua_State *L, LClosure *cl) {
704 708
705static void freeobj (lua_State *L, GCObject *o) { 709static void freeobj (lua_State *L, GCObject *o) {
706 switch (o->tt) { 710 switch (o->tt) {
707 case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; 711 case LUA_TPROTO:
708 case LUA_TLCL: { 712 luaF_freeproto(L, gco2p(o));
713 break;
714 case LUA_TLCL:
709 freeLclosure(L, gco2lcl(o)); 715 freeLclosure(L, gco2lcl(o));
710 break; 716 break;
711 } 717 case LUA_TCCL:
712 case LUA_TCCL: {
713 luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); 718 luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues));
714 break; 719 break;
715 } 720 case LUA_TTABLE:
716 case LUA_TTABLE: luaH_free(L, gco2t(o)); break; 721 luaH_free(L, gco2t(o));
717 case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; 722 break;
718 case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; 723 case LUA_TTHREAD:
724 luaE_freethread(L, gco2th(o));
725 break;
726 case LUA_TUSERDATA:
727 luaM_freemem(L, o, sizeudata(gco2u(o)));
728 break;
719 case LUA_TSHRSTR: 729 case LUA_TSHRSTR:
720 luaS_remove(L, gco2ts(o)); /* remove it from hash table */ 730 luaS_remove(L, gco2ts(o)); /* remove it from hash table */
721 luaM_freemem(L, o, sizelstring(gco2ts(o)->shrlen)); 731 luaM_freemem(L, o, sizelstring(gco2ts(o)->shrlen));
722 break; 732 break;
723 case LUA_TLNGSTR: { 733 case LUA_TLNGSTR:
724 luaM_freemem(L, o, sizelstring(gco2ts(o)->u.lnglen)); 734 luaM_freemem(L, o, sizelstring(gco2ts(o)->u.lnglen));
725 break; 735 break;
726 }
727 default: lua_assert(0); 736 default: lua_assert(0);
728 } 737 }
729} 738}
@@ -793,6 +802,10 @@ static void checkSizes (lua_State *L, global_State *g) {
793} 802}
794 803
795 804
805/*
806** Get the next udata to be finalized from the 'tobefnz' list, and
807** link it back into the 'allgc' list.
808*/
796static GCObject *udata2finalize (global_State *g) { 809static GCObject *udata2finalize (global_State *g) {
797 GCObject *o = g->tobefnz; /* get first element */ 810 GCObject *o = g->tobefnz; /* get first element */
798 lua_assert(tofinalize(o)); 811 lua_assert(tofinalize(o));
@@ -882,8 +895,11 @@ static GCObject **findlast (GCObject **p) {
882 895
883 896
884/* 897/*
885** move all unreachable objects (or 'all' objects) that need 898** Move all unreachable objects (or 'all' objects) that need
886** finalization from list 'finobj' to list 'tobefnz' (to be finalized) 899** finalization from list 'finobj' to list 'tobefnz' (to be finalized).
900** (Note that objects after 'finobjold' cannot be white, so they
901** don't need to be traversed. In incremental mode, 'finobjold' is NULL,
902** so the whole list is traversed.)
887*/ 903*/
888static void separatetobefnz (global_State *g, int all) { 904static void separatetobefnz (global_State *g, int all) {
889 GCObject *curr; 905 GCObject *curr;
@@ -894,8 +910,8 @@ static void separatetobefnz (global_State *g, int all) {
894 if (!(iswhite(curr) || all)) /* not being collected? */ 910 if (!(iswhite(curr) || all)) /* not being collected? */
895 p = &curr->next; /* don't bother with it */ 911 p = &curr->next; /* don't bother with it */
896 else { 912 else {
897 if (curr == g->finobjsur) 913 if (curr == g->finobjsur) /* removing 'finobjsur'? */
898 g->finobjsur = curr->next; 914 g->finobjsur = curr->next; /* correct it */
899 *p = curr->next; /* remove 'curr' from 'finobj' list */ 915 *p = curr->next; /* remove 'curr' from 'finobj' list */
900 curr->next = *lastnext; /* link at the end of 'tobefnz' list */ 916 curr->next = *lastnext; /* link at the end of 'tobefnz' list */
901 *lastnext = curr; 917 *lastnext = curr;
@@ -921,7 +937,7 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
921 if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ 937 if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */
922 g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */ 938 g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */
923 } 939 }
924 else { 940 else { /* correct pointers into 'allgc' list, if needed */
925 if (o == g->survival) 941 if (o == g->survival)
926 g->survival = o->next; 942 g->survival = o->next;
927 if (o == g->old) 943 if (o == g->old)
@@ -948,7 +964,7 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
948*/ 964*/
949 965
950 966
951/* mask to erase all color bits (not changing gen-related stuff) */ 967/* mask to erase all color bits, not changing gen-related stuff */
952#define maskgencolors (~(bitmask(BLACKBIT) | WHITEBITS)) 968#define maskgencolors (~(bitmask(BLACKBIT) | WHITEBITS))
953 969
954#if 0 970#if 0
@@ -962,6 +978,10 @@ static int count (GCObject *p, GCObject *limit) {
962#endif 978#endif
963 979
964 980
981/*
982** Sweep a list of objects, deleting dead ones and turning
983** the non dead to old (without changing their colors).
984*/
965static void sweep2old (lua_State *L, GCObject **p) { 985static void sweep2old (lua_State *L, GCObject **p) {
966 GCObject *curr; 986 GCObject *curr;
967 while ((curr = *p) != NULL) { 987 while ((curr = *p) != NULL) {
@@ -978,35 +998,36 @@ static void sweep2old (lua_State *L, GCObject **p) {
978} 998}
979 999
980 1000
1001/*
1002** Sweep for generational mode. Delete dead objects. (Because the
1003** collection is not incremental, there are no "new white" objects
1004** during the sweep. So, any white object must be dead.) For
1005** non-dead objects, advance their ages and clear the color of
1006** new objects. (Old objects keep their colors.)
1007*/
981static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, 1008static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
982 GCObject *limit) { 1009 GCObject *limit) {
1010 static lu_byte nextage[] = {
1011 G_SURVIVAL, /* from G_NEW */
1012 G_OLD1, /* from G_SURVIVAL */
1013 G_OLD1, /* from G_OLD0 */
1014 G_OLD, /* from G_OLD1 */
1015 G_OLD, /* from G_OLD (do not change) */
1016 G_TOUCHED1, /* from G_TOUCHED1 (do not change) */
1017 G_TOUCHED2 /* from G_TOUCHED2 (do not change) */
1018 };
983 int white = luaC_white(g); 1019 int white = luaC_white(g);
984 GCObject *curr; 1020 GCObject *curr;
985 while ((curr = *p) != limit) { 1021 while ((curr = *p) != limit) {
986 int marked = curr->marked;
987 if (iswhite(curr)) { /* is 'curr' dead? */ 1022 if (iswhite(curr)) { /* is 'curr' dead? */
988 lua_assert(!isold(curr) && !testbits(curr->marked, white)); 1023 lua_assert(!isold(curr) && isdead(g, curr));
989 *p = curr->next; /* remove 'curr' from list */ 1024 *p = curr->next; /* remove 'curr' from list */
990 freeobj(L, curr); /* erase 'curr' */ 1025 freeobj(L, curr); /* erase 'curr' */
991 } 1026 }
992 else { /* correct mark and age */ 1027 else { /* correct mark and age */
993 switch (getage(curr)) { 1028 if (getage(curr) == G_NEW)
994 case G_NEW: /* make white and go to next age */ 1029 curr->marked = cast_byte((curr->marked & maskgencolors) | white);
995 curr->marked = cast_byte((marked & maskgencolors) | white); 1030 setage(curr, nextage[getage(curr)]);
996 changeage(curr, G_NEW, G_SURVIVAL);
997 break;
998 case G_SURVIVAL: /* go to next age */
999 changeage(curr, G_SURVIVAL, G_OLD1);
1000 break;
1001 case G_OLD0: /* go to next age */
1002 changeage(curr, G_OLD0, G_OLD1);
1003 break;
1004 case G_OLD1: /* go to next age */
1005 changeage(curr, G_OLD1, G_OLD);
1006 break;
1007 default: /* don't change 'old', 'touched1', and 'touched2' */
1008 break;
1009 }
1010 p = &curr->next; /* go to next element */ 1031 p = &curr->next; /* go to next element */
1011 } 1032 }
1012 } 1033 }
@@ -1014,20 +1035,16 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
1014} 1035}
1015 1036
1016 1037
1038/*
1039** Traverse a list making all its elements white and clearing their
1040** age.
1041*/
1017static void whitelist (global_State *g, GCObject *p) { 1042static void whitelist (global_State *g, GCObject *p) {
1018 int white = luaC_white(g); 1043 int white = luaC_white(g);
1019 for (; p != NULL; p = p->next) 1044 for (; p != NULL; p = p->next)
1020 p->marked = cast_byte((p->marked & maskcolors) | white); 1045 p->marked = cast_byte((p->marked & maskcolors) | white);
1021} 1046}
1022 1047
1023
1024static void finishgencycle (lua_State *L, global_State *g) {
1025 // sweepgen(L, &g->tobefnz, ~0, mask);
1026 checkSizes(L, g);
1027 g->gcstate = GCSpropagate; /* skip restart */
1028 callallpendingfinalizers(L);
1029}
1030
1031static void printgray (GCObject *o) { 1048static void printgray (GCObject *o) {
1032 printf("gray: "); 1049 printf("gray: ");
1033 while (o) { 1050 while (o) {
@@ -1065,7 +1082,14 @@ static void printgray (GCObject *o) {
1065} 1082}
1066 1083
1067 1084
1068 1085/*
1086** Correct a list of gray objects. Because this correction is
1087** done after sweeping, young objects can be white and still
1088** be in the list. They are only removed.
1089** For tables, advance 'touched1' to 'touched2'; 'touched2' objects
1090** become regular old and are removed from the list.
1091** For threads, just remove white ones from the list.
1092*/
1069static GCObject **correctgraylist (GCObject **p) { 1093static GCObject **correctgraylist (GCObject **p) {
1070 GCObject *curr; 1094 GCObject *curr;
1071 while ((curr = *p) != NULL) { 1095 while ((curr = *p) != NULL) {
@@ -1105,6 +1129,9 @@ static GCObject **correctgraylist (GCObject **p) {
1105} 1129}
1106 1130
1107 1131
1132/*
1133** Correct all gray lists, coalescing them into 'grayagain'.
1134*/
1108static void correctgraylists (global_State *g) { 1135static void correctgraylists (global_State *g) {
1109 GCObject **list = correctgraylist(&g->grayagain); 1136 GCObject **list = correctgraylist(&g->grayagain);
1110 *list = g->weak; g->weak = NULL; 1137 *list = g->weak; g->weak = NULL;
@@ -1116,30 +1143,50 @@ static void correctgraylists (global_State *g) {
1116} 1143}
1117 1144
1118 1145
1146/*
1147** Mark 'old1' objects when starting a new young collection. ('old1'
1148** tables are always black, threads are always gray.)
1149*/
1119static void markold (global_State *g, GCObject *from, GCObject *to) { 1150static void markold (global_State *g, GCObject *from, GCObject *to) {
1120 GCObject *p; 1151 GCObject *p;
1121 for (p = from; p != to; p = p->next) { 1152 for (p = from; p != to; p = p->next) {
1122 if (getage(p) == G_OLD1) { 1153 if (getage(p) == G_OLD1) {
1123 lua_assert(!iswhite(p)); 1154 lua_assert((p->tt == LUA_TTHREAD) ? isgray(p) : isblack(p));
1124 if (isblack(p)) { 1155 if (isblack(p)) {
1125 black2gray(p); /* should be '2white', but gray works too */ 1156 black2gray(p); /* should be '2white', but gray works too */
1126 reallymarkobject(g, p); 1157 reallymarkobject(g, p);
1127 } 1158 }
1128 else
1129 lua_assert(p->tt == LUA_TTHREAD); /* threads are always gray */
1130 } 1159 }
1131 } 1160 }
1132} 1161}
1133 1162
1134 1163
1164/*
1165** Finish a young-generation collection.
1166*/
1167static void finishgencycle (lua_State *L, global_State *g) {
1168 correctgraylists(g);
1169 checkSizes(L, g);
1170 g->gcstate = GCSpropagate; /* skip restart */
1171 callallpendingfinalizers(L);
1172}
1173
1174
1175/*
1176** Does a young collection. First, mark 'old1' objects. (Only survival
1177** and "recent old" lists can contain 'old1' objects. New lists cannot
1178** contain 'old1' objects, at most 'old0' objects that were already
1179** visited when marked old.) Then does the atomic step. Then,
1180** sweep all lists and advance pointers. Finally, finish the collection.
1181*/
1135static void youngcollection (lua_State *L, global_State *g) { 1182static void youngcollection (lua_State *L, global_State *g) {
1136 GCObject **psurvival; 1183 GCObject **psurvival; /* to point to first non-dead survival object */
1137 lua_assert(g->gcstate == GCSpropagate); 1184 lua_assert(g->gcstate == GCSpropagate);
1138 markold(g, g->survival, g->reallyold); 1185 markold(g, g->survival, g->reallyold);
1139 markold(g, g->finobj, g->finobjrold); /* ??? */ 1186 markold(g, g->finobj, g->finobjrold);
1140 atomic(L); 1187 atomic(L);
1141 1188
1142 /* sweep nursery */ 1189 /* sweep nursery and get a pointer to its last live element */
1143 psurvival = sweepgen(L, g, &g->allgc, g->survival); 1190 psurvival = sweepgen(L, g, &g->allgc, g->survival);
1144 /* sweep 'survival' and 'old' */ 1191 /* sweep 'survival' and 'old' */
1145 sweepgen(L, g, psurvival, g->reallyold); 1192 sweepgen(L, g, psurvival, g->reallyold);
@@ -1158,13 +1205,15 @@ static void youngcollection (lua_State *L, global_State *g) {
1158 sweepgen(L, g, &g->tobefnz, NULL); 1205 sweepgen(L, g, &g->tobefnz, NULL);
1159 1206
1160 finishgencycle(L, g); 1207 finishgencycle(L, g);
1161 correctgraylists(g);
1162//printf("check: \n");lua_checkmemory(L);
1163} 1208}
1164 1209
1165 1210
1211/*
1212** Enter generational mode. Must go until the end of an atomic cycle
1213** to ensure that all threads are in the gray list. Then, turn all
1214** objects into old and finishes the collection.
1215*/
1166static void entergen (lua_State *L, global_State *g) { 1216static void entergen (lua_State *L, global_State *g) {
1167 lua_assert(g->reallyold == NULL && g->old == NULL && g->survival == NULL);
1168 luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */ 1217 luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */
1169 luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ 1218 luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
1170 atomic(L); 1219 atomic(L);
@@ -1177,12 +1226,18 @@ static void entergen (lua_State *L, global_State *g) {
1177 sweep2old(L, &g->finobj); 1226 sweep2old(L, &g->finobj);
1178 g->finobjrold = g->finobjold = g->finobjsur = g->finobj; 1227 g->finobjrold = g->finobjold = g->finobjsur = g->finobj;
1179 1228
1229 sweep2old(L, &g->tobefnz);
1230
1180 finishgencycle(L, g); 1231 finishgencycle(L, g);
1181 correctgraylists(g);
1182 g->gckind = KGC_GEN; 1232 g->gckind = KGC_GEN;
1183} 1233}
1184 1234
1185 1235
1236/*
1237** Enter incremental mode. Turn all objects white, make all
1238** intermediate lists point to NULL (to avoid invalid pointers),
1239** and go to pause state.
1240*/
1186static void enterinc (global_State *g) { 1241static void enterinc (global_State *g) {
1187 makewhite(g, g->mainthread); 1242 makewhite(g, g->mainthread);
1188 whitelist(g, g->allgc); 1243 whitelist(g, g->allgc);
@@ -1195,9 +1250,12 @@ static void enterinc (global_State *g) {
1195} 1250}
1196 1251
1197 1252
1253/*
1254** Change collector mode to 'newmode'.
1255*/
1198void luaC_changemode (lua_State *L, int newmode) { 1256void luaC_changemode (lua_State *L, int newmode) {
1199 global_State *g = G(L); 1257 global_State *g = G(L);
1200 if (newmode != g->gckind) { /* otherwise, nothing to be done */ 1258 if (newmode != g->gckind) {
1201 if (newmode == KGC_GEN) /* entering generational mode? */ 1259 if (newmode == KGC_GEN) /* entering generational mode? */
1202 entergen(L, g); 1260 entergen(L, g);
1203 else 1261 else
@@ -1206,12 +1264,19 @@ void luaC_changemode (lua_State *L, int newmode) {
1206} 1264}
1207 1265
1208 1266
1267/*
1268** Does a full collection in generational mode.
1269*/
1209static void fullgen (lua_State *L, global_State *g) { 1270static void fullgen (lua_State *L, global_State *g) {
1210 enterinc(g); 1271 enterinc(g);
1211 entergen(L, g); 1272 entergen(L, g);
1212} 1273}
1213 1274
1214 1275
1276/*
1277** Does a generational "step". For now that means a young
1278** collection. (We still has to implement the full control.)
1279*/
1215static void genstep (lua_State *L, global_State *g) { 1280static void genstep (lua_State *L, global_State *g) {
1216 lu_mem mem; 1281 lu_mem mem;
1217 youngcollection(L, g); 1282 youngcollection(L, g);