diff options
| -rw-r--r-- | lgc.c | 191 | ||||
| -rw-r--r-- | lgc.h | 6 |
2 files changed, 131 insertions, 66 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); |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lgc.h,v 2.92 2017/02/23 21:07:34 roberto Exp roberto $ | 2 | ** $Id: lgc.h,v 2.94 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 | */ |
| @@ -109,8 +109,8 @@ | |||
| 109 | /* object age in generational mode */ | 109 | /* object age in generational mode */ |
| 110 | #define G_NEW 0 /* created in current cycle */ | 110 | #define G_NEW 0 /* created in current cycle */ |
| 111 | #define G_SURVIVAL 1 /* created in previous cycle */ | 111 | #define G_SURVIVAL 1 /* created in previous cycle */ |
| 112 | #define G_OLD1 2 /* first full cycle as old */ | 112 | #define G_OLD0 2 /* marked old by frw. barrier in this cycle */ |
| 113 | #define G_OLD0 3 /* marked old by frw. barrier in this cycle */ | 113 | #define G_OLD1 3 /* first full cycle as old */ |
| 114 | #define G_OLD 4 /* really old object (not to be visited) */ | 114 | #define G_OLD 4 /* really old object (not to be visited) */ |
| 115 | #define G_TOUCHED1 5 /* old object touched this cycle */ | 115 | #define G_TOUCHED1 5 /* old object touched this cycle */ |
| 116 | #define G_TOUCHED2 6 /* old object touched in previous cycle */ | 116 | #define G_TOUCHED2 6 /* old object touched in previous cycle */ |
