diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-04-10 10:33:04 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-04-10 10:33:04 -0300 |
commit | 9569ad6b0ddcde43eb893d2cfe5bcdb715c0ff20 (patch) | |
tree | 8b53a4007fb476d59a8f83cbb3f97b0254f93f1b /lgc.c | |
parent | 2331e1beec01babf78ca09fea8701b5bb3c78d4c (diff) | |
download | lua-9569ad6b0ddcde43eb893d2cfe5bcdb715c0ff20.tar.gz lua-9569ad6b0ddcde43eb893d2cfe5bcdb715c0ff20.tar.bz2 lua-9569ad6b0ddcde43eb893d2cfe5bcdb715c0ff20.zip |
Comments for generational collector
Diffstat (limited to 'lgc.c')
-rw-r--r-- | lgc.c | 191 |
1 files changed, 128 insertions, 63 deletions
@@ -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) { | |||
171 | void luaC_barrierback_ (lua_State *L, Table *t) { | 171 | void 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 | */ |
398 | static int traverseephemeron (global_State *g, Table *h) { | 398 | static 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) { | |||
524 | static lu_mem traverseLclosure (global_State *g, LClosure *cl) { | 524 | static 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 | */ | ||
686 | void luaC_upvdeccount (lua_State *L, UpVal *uv) { | 690 | void 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 | ||
705 | static void freeobj (lua_State *L, GCObject *o) { | 709 | static 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 | */ | ||
796 | static GCObject *udata2finalize (global_State *g) { | 809 | static 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 | */ |
888 | static void separatetobefnz (global_State *g, int all) { | 904 | static 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 | */ | ||
965 | static void sweep2old (lua_State *L, GCObject **p) { | 985 | static 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 | */ | ||
981 | static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, | 1008 | static 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 | */ | ||
1017 | static void whitelist (global_State *g, GCObject *p) { | 1042 | static 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 | |||
1024 | static 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 | |||
1031 | static void printgray (GCObject *o) { | 1048 | static 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 | */ | ||
1069 | static GCObject **correctgraylist (GCObject **p) { | 1093 | static 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 | */ | ||
1108 | static void correctgraylists (global_State *g) { | 1135 | static 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 | */ | ||
1119 | static void markold (global_State *g, GCObject *from, GCObject *to) { | 1150 | static 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 | */ | ||
1167 | static 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 | */ | ||
1135 | static void youngcollection (lua_State *L, global_State *g) { | 1182 | static 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 | */ | ||
1166 | static void entergen (lua_State *L, global_State *g) { | 1216 | static 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 | */ | ||
1186 | static void enterinc (global_State *g) { | 1241 | static 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 | */ | ||
1198 | void luaC_changemode (lua_State *L, int newmode) { | 1256 | void 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 | */ | ||
1209 | static void fullgen (lua_State *L, global_State *g) { | 1270 | static 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 | */ | ||
1215 | static void genstep (lua_State *L, global_State *g) { | 1280 | static void genstep (lua_State *L, global_State *g) { |
1216 | lu_mem mem; | 1281 | lu_mem mem; |
1217 | youngcollection(L, g); | 1282 | youngcollection(L, g); |