aboutsummaryrefslogtreecommitdiff
path: root/lgc.c
diff options
context:
space:
mode:
Diffstat (limited to 'lgc.c')
-rw-r--r--lgc.c359
1 files changed, 276 insertions, 83 deletions
diff --git a/lgc.c b/lgc.c
index 44e5dc31..8d185cd7 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.c,v 2.215 2016/12/22 13:08:50 roberto Exp roberto $ 2** $Id: lgc.c,v 2.216 2017/02/23 21:07:34 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*/
@@ -9,7 +9,7 @@
9 9
10#include "lprefix.h" 10#include "lprefix.h"
11 11
12 12#include <stdio.h>
13#include <string.h> 13#include <string.h>
14 14
15#include "lua.h" 15#include "lua.h"
@@ -27,12 +27,6 @@
27 27
28 28
29/* 29/*
30** internal state for collector while inside the atomic phase. The
31** collector should never be in this state while running regular code.
32*/
33#define GCSinsideatomic (GCSpause + 1)
34
35/*
36** cost of sweeping one element (the size of a small object divided 30** cost of sweeping one element (the size of a small object divided
37** by some adjust for the sweep speed) 31** by some adjust for the sweep speed)
38*/ 32*/
@@ -59,8 +53,9 @@
59#define PAUSEADJ 100 53#define PAUSEADJ 100
60 54
61 55
62/* mask to erase all color bits */ 56/* mask to erase all color bits (plus gen. related stuff) */
63#define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS)) 57#define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS | AGEBITS))
58
64 59
65/* macro to erase all color bits then sets only the current white bit */ 60/* macro to erase all color bits then sets only the current white bit */
66#define makewhite(g,x) \ 61#define makewhite(g,x) \
@@ -157,8 +152,10 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
157 lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); 152 lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
158 if (keepinvariant(g)) { /* must keep invariant? */ 153 if (keepinvariant(g)) { /* must keep invariant? */
159 reallymarkobject(g, v); /* restore invariant */ 154 reallymarkobject(g, v); /* restore invariant */
160 if (isold(o)) 155 if (isold(o)) {
161 l_setbit((v)->marked, OLDBIT); 156 lua_assert(!isold(v));
157 setage(v, G_OLD0);
158 }
162 } 159 }
163 else { /* sweep phase */ 160 else { /* sweep phase */
164 lua_assert(issweepphase(g)); 161 lua_assert(issweepphase(g));
@@ -174,8 +171,12 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
174void luaC_barrierback_ (lua_State *L, Table *t) { 171void luaC_barrierback_ (lua_State *L, Table *t) {
175 global_State *g = G(L); 172 global_State *g = G(L);
176 lua_assert(isblack(t) && !isdead(g, t)); 173 lua_assert(isblack(t) && !isdead(g, t));
174 lua_assert(issweepphase(g) || getage(t) != G_TOUCHED1);
175 lua_assert(g->gckind != KGC_GEN || isold(t));
176 if (getage(t) != G_TOUCHED2) /* not already in gray list? */
177 linkgclist(t, g->grayagain); /* link it in 'grayagain' */
177 black2gray(t); /* make table gray (again) */ 178 black2gray(t); /* make table gray (again) */
178 linkgclist(t, g->grayagain); 179 setage(t, G_TOUCHED1); /* touched in current cycle */
179} 180}
180 181
181 182
@@ -188,10 +189,10 @@ void luaC_barrierback_ (lua_State *L, Table *t) {
188void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) { 189void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) {
189 global_State *g = G(L); 190 global_State *g = G(L);
190 GCObject *o = gcvalue(uv->v); 191 GCObject *o = gcvalue(uv->v);
191 lua_assert(!upisopen(uv)); /* ensured by macro luaC_upvalbarrier */
192 if (keepinvariant(g)) { 192 if (keepinvariant(g)) {
193 markobject(g, o); 193 markobject(g, o);
194 l_setbit((o)->marked, OLDBIT); 194 if (!isold(o))
195 setage(o, G_OLD0);
195 } 196 }
196} 197}
197 198
@@ -379,10 +380,10 @@ static void traverseweakvalue (global_State *g, Table *h) {
379 hasclears = 1; /* table will have to be cleared */ 380 hasclears = 1; /* table will have to be cleared */
380 } 381 }
381 } 382 }
382 if (g->gcstate == GCSpropagate) 383 if (g->gcstate == GCSatomic && hasclears)
383 linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */
384 else if (hasclears)
385 linkgclist(h, g->weak); /* has to be cleared later */ 384 linkgclist(h, g->weak); /* has to be cleared later */
385 else
386 linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */
386} 387}
387 388
388 389
@@ -431,6 +432,8 @@ static int traverseephemeron (global_State *g, Table *h) {
431 linkgclist(h, g->ephemeron); /* have to propagate again */ 432 linkgclist(h, g->ephemeron); /* have to propagate again */
432 else if (hasclears) /* table has white keys? */ 433 else if (hasclears) /* table has white keys? */
433 linkgclist(h, g->allweak); /* may have to clean white keys */ 434 linkgclist(h, g->allweak); /* may have to clean white keys */
435 else if (g->gckind == KGC_GEN)
436 linkgclist(h, g->grayagain); /* keep it in some list */
434 return marked; 437 return marked;
435} 438}
436 439
@@ -450,6 +453,10 @@ static void traversestrongtable (global_State *g, Table *h) {
450 markvalue(g, gval(n)); /* mark value */ 453 markvalue(g, gval(n)); /* mark value */
451 } 454 }
452 } 455 }
456 if (g->gckind == KGC_GEN) {
457 linkgclist(h, g->grayagain); /* keep it in some gray list */
458 black2gray(h);
459 }
453} 460}
454 461
455 462
@@ -522,7 +529,7 @@ static lu_mem traverseLclosure (global_State *g, LClosure *cl) {
522 for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */ 529 for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */
523 UpVal *uv = cl->upvals[i]; 530 UpVal *uv = cl->upvals[i];
524 if (uv != NULL) { 531 if (uv != NULL) {
525 if (upisopen(uv) && g->gcstate != GCSinsideatomic) 532 if (upisopen(uv) && g->gcstate != GCSatomic)
526 uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */ 533 uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */
527 else 534 else
528 markvalue(g, uv->v); 535 markvalue(g, uv->v);
@@ -536,11 +543,11 @@ static lu_mem traversethread (global_State *g, lua_State *th) {
536 StkId o = th->stack; 543 StkId o = th->stack;
537 if (o == NULL) 544 if (o == NULL)
538 return 1; /* stack not completely built yet */ 545 return 1; /* stack not completely built yet */
539 lua_assert(g->gcstate == GCSinsideatomic || 546 lua_assert(g->gcstate == GCSatomic ||
540 th->openupval == NULL || isintwups(th)); 547 th->openupval == NULL || isintwups(th));
541 for (; o < th->top; o++) /* mark live elements in the stack */ 548 for (; o < th->top; o++) /* mark live elements in the stack */
542 markvalue(g, o); 549 markvalue(g, o);
543 if (g->gcstate == GCSinsideatomic) { /* final traversal? */ 550 if (g->gcstate == GCSatomic) { /* final traversal? */
544 StkId lim = th->stack + th->stacksize; /* real end of stack */ 551 StkId lim = th->stack + th->stacksize; /* real end of stack */
545 for (; o < lim; o++) /* clear not-marked stack slice */ 552 for (; o < lim; o++) /* clear not-marked stack slice */
546 setnilvalue(o); 553 setnilvalue(o);
@@ -564,7 +571,7 @@ static lu_mem traversethread (global_State *g, lua_State *th) {
564static void propagatemark (global_State *g) { 571static void propagatemark (global_State *g) {
565 lu_mem size; 572 lu_mem size;
566 GCObject *o = g->gray; 573 GCObject *o = g->gray;
567 lua_assert(isgray(o)); 574 lua_assert(ongraylist(o));
568 gray2black(o); 575 gray2black(o);
569 switch (o->tt) { 576 switch (o->tt) {
570 case LUA_TTABLE: { 577 case LUA_TTABLE: {
@@ -638,11 +645,10 @@ static void convergeephemerons (global_State *g) {
638 645
639 646
640/* 647/*
641** clear entries with unmarked keys from all weaktables in list 'l' up 648** clear entries with unmarked keys from all weaktables in list 'l'
642** to element 'f'
643*/ 649*/
644static void clearkeys (global_State *g, GCObject *l, GCObject *f) { 650static void clearkeys (global_State *g, GCObject *l) {
645 for (; l != f; l = gco2t(l)->gclist) { 651 for (; l; l = gco2t(l)->gclist) {
646 Table *h = gco2t(l); 652 Table *h = gco2t(l);
647 Node *n, *limit = gnodelast(h); 653 Node *n, *limit = gnodelast(h);
648 for (n = gnode(h, 0); n < limit; n++) { 654 for (n = gnode(h, 0); n < limit; n++) {
@@ -885,11 +891,13 @@ static void separatetobefnz (global_State *g, int all) {
885 GCObject *curr; 891 GCObject *curr;
886 GCObject **p = &g->finobj; 892 GCObject **p = &g->finobj;
887 GCObject **lastnext = findlast(&g->tobefnz); 893 GCObject **lastnext = findlast(&g->tobefnz);
888 while ((curr = *p) != NULL) { /* traverse all finalizable objects */ 894 while ((curr = *p) != g->finobjold) { /* traverse all finalizable objects */
889 lua_assert(tofinalize(curr)); 895 lua_assert(tofinalize(curr));
890 if (!(iswhite(curr) || all)) /* not being collected? */ 896 if (!(iswhite(curr) || all)) /* not being collected? */
891 p = &curr->next; /* don't bother with it */ 897 p = &curr->next; /* don't bother with it */
892 else { 898 else {
899 if (curr == g->finobjsur)
900 g->finobjsur = curr->next;
893 *p = curr->next; /* remove 'curr' from 'finobj' list */ 901 *p = curr->next; /* remove 'curr' from 'finobj' list */
894 curr->next = *lastnext; /* link at the end of 'tobefnz' list */ 902 curr->next = *lastnext; /* link at the end of 'tobefnz' list */
895 *lastnext = curr; 903 *lastnext = curr;
@@ -915,6 +923,14 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
915 if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ 923 if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */
916 g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */ 924 g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */
917 } 925 }
926 else {
927 if (o == g->survival)
928 g->survival = o->next;
929 if (o == g->old)
930 g->old = o->next;
931 if (o == g->reallyold)
932 g->reallyold = o->next;
933 }
918 /* search for pointer pointing to 'o' */ 934 /* search for pointer pointing to 'o' */
919 for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } 935 for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ }
920 *p = o->next; /* remove 'o' from 'allgc' list */ 936 *p = o->next; /* remove 'o' from 'allgc' list */
@@ -934,31 +950,65 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
934*/ 950*/
935 951
936 952
953/* mask to erase all color bits (not changing gen-related stuff) */
954#define maskgencolors (~(bitmask(BLACKBIT) | WHITEBITS))
955
937#if 0 956#if 0
938static int count (GCObject *p, GCObject *limit) { 957static int count (GCObject *p, GCObject *limit) {
939 int res = 0; 958 int res = 0;
940 for (; p != NULL && p != limit; p = p->next) 959 for (; p != NULL && p != limit; p = p->next) {
941 res++; 960 res++;
961 }
942 return res; 962 return res;
943} 963}
944#endif 964#endif
945 965
946 966
947static GCObject **sweepgen (lua_State *L, GCObject **p, GCObject *limit, 967static void sweep2old (lua_State *L, GCObject **p) {
948 int zeromask, int onemask) { 968 GCObject *curr;
949 global_State *g = G(L); 969 while ((curr = *p) != NULL) {
950 int ow = otherwhite(g); 970 if (iswhite(curr)) { /* is 'curr' dead? */
971 lua_assert(isdead(G(L), curr));
972 *p = curr->next; /* remove 'curr' from list */
973 freeobj(L, curr); /* erase 'curr' */
974 }
975 else { /* all surviving objects become old */
976 setage(curr, G_OLD);
977 p = &curr->next; /* go to next element */
978 }
979 }
980}
981
982
983static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
984 GCObject *limit) {
985 int white = luaC_white(g);
951 GCObject *curr; 986 GCObject *curr;
952 while ((curr = *p) != limit) { 987 while ((curr = *p) != limit) {
953 int marked = curr->marked; 988 int marked = curr->marked;
954 if (isdeadm(ow, marked)) { /* is 'curr' dead? */ 989 if (iswhite(curr)) { /* is 'curr' dead? */
955 lua_assert(!isold(curr)); 990 lua_assert(!isold(curr) && !testbits(curr->marked, white));
956 *p = curr->next; /* remove 'curr' from list */ 991 *p = curr->next; /* remove 'curr' from list */
957 freeobj(L, curr); /* erase 'curr' */ 992 freeobj(L, curr); /* erase 'curr' */
958 } 993 }
959 else { /* correct mark */ 994 else { /* correct mark and age */
960 if (!isold(curr)) /* don't change old objects */ 995 switch (getage(curr)) {
961 curr->marked = cast_byte((marked & zeromask) | onemask); 996 case G_NEW: /* make white and go to next age */
997 curr->marked = cast_byte((marked & maskgencolors) | white);
998 changeage(curr, G_NEW, G_SURVIVAL);
999 break;
1000 case G_SURVIVAL: /* go to next age */
1001 changeage(curr, G_SURVIVAL, G_OLD1);
1002 break;
1003 case G_OLD0: /* go to next age */
1004 changeage(curr, G_OLD0, G_OLD1);
1005 break;
1006 case G_OLD1: /* go to next age */
1007 changeage(curr, G_OLD1, G_OLD);
1008 break;
1009 default: /* don't change 'old', 'touched1', and 'touched2' */
1010 break;
1011 }
962 p = &curr->next; /* go to next element */ 1012 p = &curr->next; /* go to next element */
963 } 1013 }
964 } 1014 }
@@ -966,51 +1016,184 @@ static GCObject **sweepgen (lua_State *L, GCObject **p, GCObject *limit,
966} 1016}
967 1017
968 1018
969static void startgencycle (lua_State *L, global_State *g) { 1019static void whitelist (global_State *g, GCObject *p) {
970 propagateall(g); 1020 int white = luaC_white(g);
971 atomic(L); 1021 for (; p != NULL; p = p->next)
1022 p->marked = cast_byte((p->marked & maskcolors) | white);
972} 1023}
973 1024
974 1025
975static void finishgencycle (lua_State *L, global_State *g, int mask) { 1026static void finishgencycle (lua_State *L, global_State *g) {
976 sweepgen(L, &g->finobj, NULL, ~0, mask); 1027 // sweepgen(L, &g->tobefnz, ~0, mask);
977 sweepgen(L, &g->tobefnz, NULL, ~0, mask);
978 checkSizes(L, g); 1028 checkSizes(L, g);
979 g->gcstate = GCSpropagate; /* skip restart */ 1029 g->gcstate = GCSpropagate; /* skip restart */
980 callallpendingfinalizers(L); 1030 callallpendingfinalizers(L);
981} 1031}
982 1032
1033static void printgray (GCObject *o) {
1034 printf("gray: ");
1035 while (o) {
1036 printf("%p %d %02x ", (void*)o, o->tt, o->marked);
1037 switch (o->tt) {
1038 case LUA_TTABLE: {
1039 Table *h = gco2t(o);
1040 o = h->gclist;
1041 break;
1042 }
1043 case LUA_TLCL: {
1044 LClosure *cl = gco2lcl(o);
1045 o = cl->gclist;
1046 break;
1047 }
1048 case LUA_TCCL: {
1049 CClosure *cl = gco2ccl(o);
1050 o = cl->gclist;
1051 break;
1052 }
1053 case LUA_TTHREAD: {
1054 lua_State *th = gco2th(o);
1055 o = th->gclist;
1056 break;
1057 }
1058 case LUA_TPROTO: {
1059 Proto *p = gco2p(o);
1060 o = p->gclist;
1061 break;
1062 }
1063 default: lua_assert(0); return;
1064 }
1065 }
1066 printf("\n");
1067}
1068
1069
1070
1071static GCObject **correctgraylist (GCObject **p) {
1072 GCObject *curr;
1073 while ((curr = *p) != NULL) {
1074 switch (curr->tt) {
1075 case LUA_TTABLE: {
1076 Table *h = gco2t(curr);
1077 if (getage(h) == G_TOUCHED1) { /* touched in this cycle? */
1078 lua_assert(isgray(h));
1079 gray2black(h); /* make it black, for next barrier */
1080 changeage(h, G_TOUCHED1, G_TOUCHED2);
1081 p = &h->gclist; /* go to next element */
1082 }
1083 else {
1084 if (!iswhite(h)) {
1085 lua_assert(isold(h));
1086 if (getage(h) == G_TOUCHED2)
1087 changeage(h, G_TOUCHED2, G_OLD);
1088 gray2black(h); /* make it black */
1089 }
1090 *p = h->gclist; /* remove 'curr' from gray list */
1091 }
1092 break;
1093 }
1094 case LUA_TTHREAD: {
1095 lua_State *th = gco2th(curr);
1096 lua_assert(!isblack(th));
1097 if (iswhite(th)) /* new object? */
1098 *p = th->gclist; /* remove from gray list */
1099 else /* old threads remain gray */
1100 p = &th->gclist; /* go to next element */
1101 break;
1102 }
1103 default: lua_assert(0); /* nothing more could be gray here */
1104 }
1105 }
1106 return p;
1107}
1108
1109
1110static void correctgraylists (global_State *g) {
1111 GCObject **list = correctgraylist(&g->grayagain);
1112 *list = g->weak; g->weak = NULL;
1113 list = correctgraylist(list);
1114 *list = g->allweak; g->allweak = NULL;
1115 list = correctgraylist(list);
1116 *list = g->ephemeron; g->ephemeron = NULL;
1117 correctgraylist(list);
1118}
1119
1120
1121static void markold (global_State *g, GCObject *from, GCObject *to) {
1122 GCObject *p;
1123 for (p = from; p != to; p = p->next) {
1124 if (getage(p) == G_OLD1) {
1125 lua_assert(!iswhite(p));
1126 if (isblack(p)) {
1127 black2gray(p); /* should be '2white', but gray works too */
1128 reallymarkobject(g, p);
1129 }
1130 else
1131 lua_assert(p->tt == LUA_TTHREAD); /* threads are always gray */
1132 }
1133 }
1134}
1135
983 1136
984static void youngcollection (lua_State *L, global_State *g) { 1137static void youngcollection (lua_State *L, global_State *g) {
985 GCObject **psurvival; 1138 GCObject **psurvival;
986 lua_assert(g->gcstate == GCSpropagate); 1139 lua_assert(g->gcstate == GCSpropagate);
987 startgencycle(L, g); 1140 markold(g, g->survival, g->reallyold);
1141 markold(g, g->finobj, g->finobjrold); /* ??? */
1142 atomic(L);
1143
988 /* sweep nursery */ 1144 /* sweep nursery */
989 psurvival = sweepgen(L, &g->allgc, g->survival, maskcolors, luaC_white(g)); 1145 psurvival = sweepgen(L, g, &g->allgc, g->survival);
990 lua_assert(*psurvival == g->survival); 1146 /* sweep 'survival' and 'old' */
991 /* sweep 'survival' list, making elements old */ 1147 sweepgen(L, g, psurvival, g->reallyold);
992 sweepgen(L, psurvival, g->old, ~0, bitmask(OLDBIT)); 1148 g->reallyold = g->old;
993 /* incorporate 'survival' list into old list */ 1149 g->old = *psurvival; /* 'survival' survivals are old now */
994 g->old = *psurvival; 1150 g->survival = g->allgc; /* all news are survivals */
995 /* surviving young objects go to 'survival' list */ 1151
996 g->survival = g->allgc; 1152 /* repeat for 'finobj' lists */
997 finishgencycle(L, g, 0); 1153 psurvival = sweepgen(L, g, &g->finobj, g->finobjsur);
998lua_checkmemory(L); 1154 /* sweep 'survival' and 'old' */
1155 sweepgen(L, g, psurvival, g->finobjrold);
1156 g->finobjrold = g->finobjold;
1157 g->finobjold = *psurvival; /* 'survival' survivals are old now */
1158 g->finobjsur = g->finobj; /* all news are survivals */
1159
1160 sweepgen(L, g, &g->tobefnz, NULL);
1161
1162 finishgencycle(L, g);
1163 correctgraylists(g);
1164//printf("check: \n");lua_checkmemory(L);
999} 1165}
1000 1166
1001 1167
1002static void entergen (lua_State *L, global_State *g) { 1168static void entergen (lua_State *L, global_State *g) {
1003lua_checkmemory(L); 1169 lua_assert(g->reallyold == NULL && g->old == NULL && g->survival == NULL);
1004 lua_assert(g->old == NULL && g->survival == NULL);
1005 luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */ 1170 luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */
1006 luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ 1171 luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
1007 startgencycle(L, g); 1172 atomic(L);
1008 /* sweep all ellements making them old */ 1173 /* sweep all ellements making them old */
1009 sweepgen(L, &g->allgc, g->survival, ~0, bitmask(OLDBIT)); 1174 sweep2old(L, &g->allgc);
1010 /* everything alive now is old; 'survival' is empty */ 1175 /* everything alive now is old */
1011 g->old = g->survival = g->allgc; 1176 g->reallyold = g->old = g->survival = g->allgc;
1012 finishgencycle(L, g, bitmask(OLDBIT)); 1177
1013lua_checkmemory(L); 1178 /* repeat for 'finobj' lists */
1179 sweep2old(L, &g->finobj);
1180 g->finobjrold = g->finobjold = g->finobjsur = g->finobj;
1181
1182 finishgencycle(L, g);
1183 correctgraylists(g);
1184 g->gckind = KGC_GEN;
1185}
1186
1187
1188static void enterinc (global_State *g) {
1189 makewhite(g, g->mainthread);
1190 whitelist(g, g->allgc);
1191 g->reallyold = g->old = g->survival = NULL;
1192 whitelist(g, g->finobj);
1193 g->finobjrold = g->finobjold = g->finobjsur = NULL;
1194 lua_assert(g->tobefnz == NULL); /* no need to sweep */
1195 g->gcstate = GCSpause;
1196 g->gckind = KGC_NORMAL;
1014} 1197}
1015 1198
1016 1199
@@ -1019,17 +1202,18 @@ void luaC_changemode (lua_State *L, int newmode) {
1019 if (newmode != g->gckind) { /* otherwise, nothing to be done */ 1202 if (newmode != g->gckind) { /* otherwise, nothing to be done */
1020 if (newmode == KGC_GEN) /* entering generational mode? */ 1203 if (newmode == KGC_GEN) /* entering generational mode? */
1021 entergen(L, g); 1204 entergen(L, g);
1022 else { /* entering incremental mode */ 1205 else
1023lua_checkmemory(L); 1206 enterinc(g); /* entering incremental mode */
1024 youngcollection(L, g);
1025 g->old = g->survival = NULL;
1026lua_checkmemory(L);
1027 }
1028 g->gckind = newmode;
1029 } 1207 }
1030} 1208}
1031 1209
1032 1210
1211static void fullgen (lua_State *L, global_State *g) {
1212 enterinc(g);
1213 entergen(L, g);
1214}
1215
1216
1033static void genstep (lua_State *L, global_State *g) { 1217static void genstep (lua_State *L, global_State *g) {
1034 lu_mem mem; 1218 lu_mem mem;
1035 youngcollection(L, g); 1219 youngcollection(L, g);
@@ -1094,10 +1278,10 @@ static void deletealllist (lua_State *L, GCObject *p) {
1094 1278
1095void luaC_freeallobjects (lua_State *L) { 1279void luaC_freeallobjects (lua_State *L) {
1096 global_State *g = G(L); 1280 global_State *g = G(L);
1281 luaC_changemode(L, KGC_NORMAL);
1097 separatetobefnz(g, 1); /* separate all objects with finalizers */ 1282 separatetobefnz(g, 1); /* separate all objects with finalizers */
1098 lua_assert(g->finobj == NULL); 1283 lua_assert(g->finobj == NULL);
1099 callallpendingfinalizers(L); 1284 callallpendingfinalizers(L);
1100 lua_assert(g->tobefnz == NULL);
1101 deletealllist(L, g->finobj); 1285 deletealllist(L, g->finobj);
1102 deletealllist(L, g->allgc); 1286 deletealllist(L, g->allgc);
1103 deletealllist(L, g->fixedgc); /* collect fixed objects */ 1287 deletealllist(L, g->fixedgc); /* collect fixed objects */
@@ -1110,9 +1294,10 @@ static l_mem atomic (lua_State *L) {
1110 l_mem work; 1294 l_mem work;
1111 GCObject *origweak, *origall; 1295 GCObject *origweak, *origall;
1112 GCObject *grayagain = g->grayagain; /* save original list */ 1296 GCObject *grayagain = g->grayagain; /* save original list */
1297 g->grayagain = NULL;
1113 lua_assert(g->ephemeron == NULL && g->weak == NULL); 1298 lua_assert(g->ephemeron == NULL && g->weak == NULL);
1114 lua_assert(!iswhite(g->mainthread)); 1299 lua_assert(!iswhite(g->mainthread));
1115 g->gcstate = GCSinsideatomic; 1300 g->gcstate = GCSatomic;
1116 g->GCmemtrav = 0; /* start counting work */ 1301 g->GCmemtrav = 0; /* start counting work */
1117 markobject(g, L); /* mark running thread */ 1302 markobject(g, L); /* mark running thread */
1118 /* registry and global metatables may be changed by API */ 1303 /* registry and global metatables may be changed by API */
@@ -1123,7 +1308,6 @@ static l_mem atomic (lua_State *L) {
1123 propagateall(g); /* propagate changes */ 1308 propagateall(g); /* propagate changes */
1124 work = g->GCmemtrav; /* stop counting (do not recount 'grayagain') */ 1309 work = g->GCmemtrav; /* stop counting (do not recount 'grayagain') */
1125 g->gray = grayagain; 1310 g->gray = grayagain;
1126 g->grayagain = NULL;
1127 propagateall(g); /* traverse 'grayagain' list */ 1311 propagateall(g); /* traverse 'grayagain' list */
1128 g->GCmemtrav = 0; /* restart counting */ 1312 g->GCmemtrav = 0; /* restart counting */
1129 convergeephemerons(g); 1313 convergeephemerons(g);
@@ -1141,13 +1325,14 @@ static l_mem atomic (lua_State *L) {
1141 convergeephemerons(g); 1325 convergeephemerons(g);
1142 /* at this point, all resurrected objects are marked. */ 1326 /* at this point, all resurrected objects are marked. */
1143 /* remove dead objects from weak tables */ 1327 /* remove dead objects from weak tables */
1144 clearkeys(g, g->ephemeron, NULL); /* clear keys from all ephemeron tables */ 1328 clearkeys(g, g->ephemeron); /* clear keys from all ephemeron tables */
1145 clearkeys(g, g->allweak, NULL); /* clear keys from all 'allweak' tables */ 1329 clearkeys(g, g->allweak); /* clear keys from all 'allweak' tables */
1146 /* clear values from resurrected weak tables */ 1330 /* clear values from resurrected weak tables */
1147 clearvalues(g, g->weak, origweak); 1331 clearvalues(g, g->weak, origweak);
1148 clearvalues(g, g->allweak, origall); 1332 clearvalues(g, g->allweak, origall);
1149 luaS_clearcache(g); 1333 luaS_clearcache(g);
1150 g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ 1334 g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
1335 lua_assert(g->gray == NULL);
1151 work += g->GCmemtrav; /* complete counting */ 1336 work += g->GCmemtrav; /* complete counting */
1152 return work; /* estimate of memory marked by 'atomic' */ 1337 return work; /* estimate of memory marked by 'atomic' */
1153} 1338}
@@ -1181,12 +1366,12 @@ static lu_mem singlestep (lua_State *L) {
1181 case GCSpropagate: { 1366 case GCSpropagate: {
1182 g->GCmemtrav = 0; 1367 g->GCmemtrav = 0;
1183 if (g->gray == NULL) /* no more gray objects? */ 1368 if (g->gray == NULL) /* no more gray objects? */
1184 g->gcstate = GCSatomic; /* finish propagate phase */ 1369 g->gcstate = GCSenteratomic; /* finish propagate phase */
1185 else 1370 else
1186 propagatemark(g); /* traverse one gray object */ 1371 propagatemark(g); /* traverse one gray object */
1187 return g->GCmemtrav; /* memory traversed in this step */ 1372 return g->GCmemtrav; /* memory traversed in this step */
1188 } 1373 }
1189 case GCSatomic: { 1374 case GCSenteratomic: {
1190 lu_mem work; 1375 lu_mem work;
1191 propagateall(g); /* make sure gray list is empty */ 1376 propagateall(g); /* make sure gray list is empty */
1192 work = atomic(L); /* work is what was traversed by 'atomic' */ 1377 work = atomic(L); /* work is what was traversed by 'atomic' */
@@ -1291,23 +1476,31 @@ void luaC_step (lua_State *L) {
1291** to sweep all objects to turn them back to white (as white has not 1476** to sweep all objects to turn them back to white (as white has not
1292** changed, nothing will be collected). 1477** changed, nothing will be collected).
1293*/ 1478*/
1294void luaC_fullgc (lua_State *L, int isemergency) { 1479static void fullinc (lua_State *L, global_State *g) {
1295 global_State *g = G(L); 1480 if (keepinvariant(g)) /* black objects? */
1296 lua_assert(g->gckind == KGC_NORMAL);
1297 if (isemergency) g->gckind = KGC_EMERGENCY; /* set flag */
1298 if (keepinvariant(g)) { /* black objects? */
1299 entersweep(L); /* sweep everything to turn them back to white */ 1481 entersweep(L); /* sweep everything to turn them back to white */
1300 }
1301 /* finish any pending sweep phase to start a new cycle */ 1482 /* finish any pending sweep phase to start a new cycle */
1302 luaC_runtilstate(L, bitmask(GCSpause)); 1483 luaC_runtilstate(L, bitmask(GCSpause));
1303 luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ 1484 luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */
1304 /* estimate must be correct after a full GC cycle */ 1485 /* estimate must be correct after a full GC cycle */
1305 lua_assert(g->GCestimate == gettotalbytes(g)); 1486 lua_assert(g->GCestimate == gettotalbytes(g));
1306 luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ 1487 luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */
1307 g->gckind = KGC_NORMAL;
1308 setpause(g); 1488 setpause(g);
1309} 1489}
1310 1490
1491
1492void luaC_fullgc (lua_State *L, int isemergency) {
1493 global_State *g = G(L);
1494 int gckind = g->gckind;
1495 if (isemergency)
1496 g->gckind = KGC_EMERGENCY; /* set flag */
1497 if (gckind == KGC_NORMAL)
1498 fullinc(L, g);
1499 else
1500 fullgen(L, g);
1501 g->gckind = gckind;
1502}
1503
1311/* }====================================================== */ 1504/* }====================================================== */
1312 1505
1313 1506