diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-02-23 18:07:34 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-02-23 18:07:34 -0300 |
commit | f5f3df3bd17fb3489bbd26ab39fe1580a8dbf9c9 (patch) | |
tree | 84f67f71a728bc988661349c361f2a968b1d4910 /lgc.c | |
parent | e6c1e6005a9346d378e004a6d6e7fd98c7ee191b (diff) | |
download | lua-f5f3df3bd17fb3489bbd26ab39fe1580a8dbf9c9.tar.gz lua-f5f3df3bd17fb3489bbd26ab39fe1580a8dbf9c9.tar.bz2 lua-f5f3df3bd17fb3489bbd26ab39fe1580a8dbf9c9.zip |
generational collection: new attempt (still incomplete)
Diffstat (limited to 'lgc.c')
-rw-r--r-- | lgc.c | 183 |
1 files changed, 159 insertions, 24 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.214 2016/11/07 12:38:35 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.215 2016/12/22 13:08:50 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 | */ |
@@ -59,11 +59,10 @@ | |||
59 | #define PAUSEADJ 100 | 59 | #define PAUSEADJ 100 |
60 | 60 | ||
61 | 61 | ||
62 | /* | 62 | /* mask to erase all color bits */ |
63 | ** 'makewhite' erases all color bits then sets only the current white | ||
64 | ** bit | ||
65 | */ | ||
66 | #define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS)) | 63 | #define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS)) |
64 | |||
65 | /* macro to erase all color bits then sets only the current white bit */ | ||
67 | #define makewhite(g,x) \ | 66 | #define makewhite(g,x) \ |
68 | (x->marked = cast_byte((x->marked & maskcolors) | luaC_white(g))) | 67 | (x->marked = cast_byte((x->marked & maskcolors) | luaC_white(g))) |
69 | 68 | ||
@@ -92,6 +91,7 @@ | |||
92 | #define markobjectN(g,t) { if (t) markobject(g,t); } | 91 | #define markobjectN(g,t) { if (t) markobject(g,t); } |
93 | 92 | ||
94 | static void reallymarkobject (global_State *g, GCObject *o); | 93 | static void reallymarkobject (global_State *g, GCObject *o); |
94 | static l_mem atomic (lua_State *L); | ||
95 | 95 | ||
96 | 96 | ||
97 | /* | 97 | /* |
@@ -155,8 +155,11 @@ static int iscleared (global_State *g, const TValue *o) { | |||
155 | void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { | 155 | void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { |
156 | global_State *g = G(L); | 156 | global_State *g = G(L); |
157 | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); | 157 | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); |
158 | if (keepinvariant(g)) /* must keep invariant? */ | 158 | if (keepinvariant(g)) { /* must keep invariant? */ |
159 | reallymarkobject(g, v); /* restore invariant */ | 159 | reallymarkobject(g, v); /* restore invariant */ |
160 | if (isold(o)) | ||
161 | l_setbit((v)->marked, OLDBIT); | ||
162 | } | ||
160 | else { /* sweep phase */ | 163 | else { /* sweep phase */ |
161 | lua_assert(issweepphase(g)); | 164 | lua_assert(issweepphase(g)); |
162 | makewhite(g, o); /* mark main obj. as white to avoid other barriers */ | 165 | makewhite(g, o); /* mark main obj. as white to avoid other barriers */ |
@@ -186,8 +189,10 @@ void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) { | |||
186 | global_State *g = G(L); | 189 | global_State *g = G(L); |
187 | GCObject *o = gcvalue(uv->v); | 190 | GCObject *o = gcvalue(uv->v); |
188 | lua_assert(!upisopen(uv)); /* ensured by macro luaC_upvalbarrier */ | 191 | lua_assert(!upisopen(uv)); /* ensured by macro luaC_upvalbarrier */ |
189 | if (keepinvariant(g)) | 192 | if (keepinvariant(g)) { |
190 | markobject(g, o); | 193 | markobject(g, o); |
194 | l_setbit((o)->marked, OLDBIT); | ||
195 | } | ||
191 | } | 196 | } |
192 | 197 | ||
193 | 198 | ||
@@ -922,6 +927,121 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { | |||
922 | /* }====================================================== */ | 927 | /* }====================================================== */ |
923 | 928 | ||
924 | 929 | ||
930 | /* | ||
931 | ** {====================================================== | ||
932 | ** Generational Collector | ||
933 | ** ======================================================= | ||
934 | */ | ||
935 | |||
936 | |||
937 | #if 0 | ||
938 | static int count (GCObject *p, GCObject *limit) { | ||
939 | int res = 0; | ||
940 | for (; p != NULL && p != limit; p = p->next) | ||
941 | res++; | ||
942 | return res; | ||
943 | } | ||
944 | #endif | ||
945 | |||
946 | |||
947 | static GCObject **sweepgen (lua_State *L, GCObject **p, GCObject *limit, | ||
948 | int zeromask, int onemask) { | ||
949 | global_State *g = G(L); | ||
950 | int ow = otherwhite(g); | ||
951 | GCObject *curr; | ||
952 | while ((curr = *p) != limit) { | ||
953 | int marked = curr->marked; | ||
954 | if (isdeadm(ow, marked)) { /* is 'curr' dead? */ | ||
955 | lua_assert(!isold(curr)); | ||
956 | *p = curr->next; /* remove 'curr' from list */ | ||
957 | freeobj(L, curr); /* erase 'curr' */ | ||
958 | } | ||
959 | else { /* correct mark */ | ||
960 | if (!isold(curr)) /* don't change old objects */ | ||
961 | curr->marked = cast_byte((marked & zeromask) | onemask); | ||
962 | p = &curr->next; /* go to next element */ | ||
963 | } | ||
964 | } | ||
965 | return p; | ||
966 | } | ||
967 | |||
968 | |||
969 | static void startgencycle (lua_State *L, global_State *g) { | ||
970 | propagateall(g); | ||
971 | atomic(L); | ||
972 | } | ||
973 | |||
974 | |||
975 | static void finishgencycle (lua_State *L, global_State *g, int mask) { | ||
976 | sweepgen(L, &g->finobj, NULL, ~0, mask); | ||
977 | sweepgen(L, &g->tobefnz, NULL, ~0, mask); | ||
978 | checkSizes(L, g); | ||
979 | g->gcstate = GCSpropagate; /* skip restart */ | ||
980 | callallpendingfinalizers(L); | ||
981 | } | ||
982 | |||
983 | |||
984 | static void youngcollection (lua_State *L, global_State *g) { | ||
985 | GCObject **psurvival; | ||
986 | lua_assert(g->gcstate == GCSpropagate); | ||
987 | startgencycle(L, g); | ||
988 | /* sweep nursery */ | ||
989 | psurvival = sweepgen(L, &g->allgc, g->survival, maskcolors, luaC_white(g)); | ||
990 | lua_assert(*psurvival == g->survival); | ||
991 | /* sweep 'survival' list, making elements old */ | ||
992 | sweepgen(L, psurvival, g->old, ~0, bitmask(OLDBIT)); | ||
993 | /* incorporate 'survival' list into old list */ | ||
994 | g->old = *psurvival; | ||
995 | /* surviving young objects go to 'survival' list */ | ||
996 | g->survival = g->allgc; | ||
997 | finishgencycle(L, g, 0); | ||
998 | lua_checkmemory(L); | ||
999 | } | ||
1000 | |||
1001 | |||
1002 | static void entergen (lua_State *L, global_State *g) { | ||
1003 | lua_checkmemory(L); | ||
1004 | lua_assert(g->old == NULL && g->survival == NULL); | ||
1005 | luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */ | ||
1006 | luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ | ||
1007 | startgencycle(L, g); | ||
1008 | /* sweep all ellements making them old */ | ||
1009 | sweepgen(L, &g->allgc, g->survival, ~0, bitmask(OLDBIT)); | ||
1010 | /* everything alive now is old; 'survival' is empty */ | ||
1011 | g->old = g->survival = g->allgc; | ||
1012 | finishgencycle(L, g, bitmask(OLDBIT)); | ||
1013 | lua_checkmemory(L); | ||
1014 | } | ||
1015 | |||
1016 | |||
1017 | void luaC_changemode (lua_State *L, int newmode) { | ||
1018 | global_State *g = G(L); | ||
1019 | if (newmode != g->gckind) { /* otherwise, nothing to be done */ | ||
1020 | if (newmode == KGC_GEN) /* entering generational mode? */ | ||
1021 | entergen(L, g); | ||
1022 | else { /* entering incremental mode */ | ||
1023 | lua_checkmemory(L); | ||
1024 | youngcollection(L, g); | ||
1025 | g->old = g->survival = NULL; | ||
1026 | lua_checkmemory(L); | ||
1027 | } | ||
1028 | g->gckind = newmode; | ||
1029 | } | ||
1030 | } | ||
1031 | |||
1032 | |||
1033 | static void genstep (lua_State *L, global_State *g) { | ||
1034 | lu_mem mem; | ||
1035 | youngcollection(L, g); | ||
1036 | mem = gettotalbytes(g); | ||
1037 | luaE_setdebt(g, -((mem / 100) * 20)); | ||
1038 | } | ||
1039 | |||
1040 | |||
1041 | |||
1042 | |||
1043 | /* }====================================================== */ | ||
1044 | |||
925 | 1045 | ||
926 | /* | 1046 | /* |
927 | ** {====================================================== | 1047 | ** {====================================================== |
@@ -963,17 +1083,24 @@ static void entersweep (lua_State *L) { | |||
963 | } | 1083 | } |
964 | 1084 | ||
965 | 1085 | ||
1086 | static void deletealllist (lua_State *L, GCObject *p) { | ||
1087 | while (p) { | ||
1088 | GCObject *next = p->next; | ||
1089 | freeobj(L, p); | ||
1090 | p = next; | ||
1091 | } | ||
1092 | } | ||
1093 | |||
1094 | |||
966 | void luaC_freeallobjects (lua_State *L) { | 1095 | void luaC_freeallobjects (lua_State *L) { |
967 | global_State *g = G(L); | 1096 | global_State *g = G(L); |
968 | separatetobefnz(g, 1); /* separate all objects with finalizers */ | 1097 | separatetobefnz(g, 1); /* separate all objects with finalizers */ |
969 | lua_assert(g->finobj == NULL); | 1098 | lua_assert(g->finobj == NULL); |
970 | callallpendingfinalizers(L); | 1099 | callallpendingfinalizers(L); |
971 | lua_assert(g->tobefnz == NULL); | 1100 | lua_assert(g->tobefnz == NULL); |
972 | g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ | 1101 | deletealllist(L, g->finobj); |
973 | g->gckind = KGC_NORMAL; | 1102 | deletealllist(L, g->allgc); |
974 | sweepwholelist(L, &g->finobj); | 1103 | deletealllist(L, g->fixedgc); /* collect fixed objects */ |
975 | sweepwholelist(L, &g->allgc); | ||
976 | sweepwholelist(L, &g->fixedgc); /* collect fixed objects */ | ||
977 | lua_assert(g->strt.nuse == 0); | 1104 | lua_assert(g->strt.nuse == 0); |
978 | } | 1105 | } |
979 | 1106 | ||
@@ -996,6 +1123,7 @@ static l_mem atomic (lua_State *L) { | |||
996 | propagateall(g); /* propagate changes */ | 1123 | propagateall(g); /* propagate changes */ |
997 | work = g->GCmemtrav; /* stop counting (do not recount 'grayagain') */ | 1124 | work = g->GCmemtrav; /* stop counting (do not recount 'grayagain') */ |
998 | g->gray = grayagain; | 1125 | g->gray = grayagain; |
1126 | g->grayagain = NULL; | ||
999 | propagateall(g); /* traverse 'grayagain' list */ | 1127 | propagateall(g); /* traverse 'grayagain' list */ |
1000 | g->GCmemtrav = 0; /* restart counting */ | 1128 | g->GCmemtrav = 0; /* restart counting */ |
1001 | convergeephemerons(g); | 1129 | convergeephemerons(g); |
@@ -1052,10 +1180,10 @@ static lu_mem singlestep (lua_State *L) { | |||
1052 | } | 1180 | } |
1053 | case GCSpropagate: { | 1181 | case GCSpropagate: { |
1054 | g->GCmemtrav = 0; | 1182 | g->GCmemtrav = 0; |
1055 | lua_assert(g->gray); | 1183 | if (g->gray == NULL) /* no more gray objects? */ |
1056 | propagatemark(g); | ||
1057 | if (g->gray == NULL) /* no more gray objects? */ | ||
1058 | g->gcstate = GCSatomic; /* finish propagate phase */ | 1184 | g->gcstate = GCSatomic; /* finish propagate phase */ |
1185 | else | ||
1186 | propagatemark(g); /* traverse one gray object */ | ||
1059 | return g->GCmemtrav; /* memory traversed in this step */ | 1187 | return g->GCmemtrav; /* memory traversed in this step */ |
1060 | } | 1188 | } |
1061 | case GCSatomic: { | 1189 | case GCSatomic: { |
@@ -1123,15 +1251,10 @@ static l_mem getdebt (global_State *g) { | |||
1123 | } | 1251 | } |
1124 | 1252 | ||
1125 | /* | 1253 | /* |
1126 | ** performs a basic GC step when collector is running | 1254 | ** performs a basic incremental step |
1127 | */ | 1255 | */ |
1128 | void luaC_step (lua_State *L) { | 1256 | static void incstep (lua_State *L, global_State *g) { |
1129 | global_State *g = G(L); | 1257 | l_mem debt = getdebt(g); /* GC deficit (to be paid now) */ |
1130 | l_mem debt = getdebt(g); /* GC deficit (be paid now) */ | ||
1131 | if (!g->gcrunning) { /* not running? */ | ||
1132 | luaE_setdebt(g, -GCSTEPSIZE * 10); /* avoid being called too often */ | ||
1133 | return; | ||
1134 | } | ||
1135 | do { /* repeat until pause or enough "credit" (negative debt) */ | 1258 | do { /* repeat until pause or enough "credit" (negative debt) */ |
1136 | lu_mem work = singlestep(L); /* perform one single step */ | 1259 | lu_mem work = singlestep(L); /* perform one single step */ |
1137 | debt -= work; | 1260 | debt -= work; |
@@ -1145,6 +1268,19 @@ void luaC_step (lua_State *L) { | |||
1145 | } | 1268 | } |
1146 | } | 1269 | } |
1147 | 1270 | ||
1271 | /* | ||
1272 | ** performs a basic GC step when collector is running | ||
1273 | */ | ||
1274 | void luaC_step (lua_State *L) { | ||
1275 | global_State *g = G(L); | ||
1276 | if (!g->gcrunning) /* not running? */ | ||
1277 | luaE_setdebt(g, -GCSTEPSIZE * 10); /* avoid being called too often */ | ||
1278 | else if (g->gckind == KGC_NORMAL) | ||
1279 | incstep(L, g); | ||
1280 | else | ||
1281 | genstep(L, g); | ||
1282 | } | ||
1283 | |||
1148 | 1284 | ||
1149 | /* | 1285 | /* |
1150 | ** Performs a full GC cycle; if 'isemergency', set a flag to avoid | 1286 | ** Performs a full GC cycle; if 'isemergency', set a flag to avoid |
@@ -1164,7 +1300,6 @@ void luaC_fullgc (lua_State *L, int isemergency) { | |||
1164 | } | 1300 | } |
1165 | /* finish any pending sweep phase to start a new cycle */ | 1301 | /* finish any pending sweep phase to start a new cycle */ |
1166 | luaC_runtilstate(L, bitmask(GCSpause)); | 1302 | luaC_runtilstate(L, bitmask(GCSpause)); |
1167 | luaC_runtilstate(L, ~bitmask(GCSpause)); /* start new collection */ | ||
1168 | luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ | 1303 | luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ |
1169 | /* estimate must be correct after a full GC cycle */ | 1304 | /* estimate must be correct after a full GC cycle */ |
1170 | lua_assert(g->GCestimate == gettotalbytes(g)); | 1305 | lua_assert(g->GCestimate == gettotalbytes(g)); |