aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lgc.c59
-rw-r--r--lstate.c2
-rw-r--r--lstate.h18
-rw-r--r--testes/gengc.lua16
4 files changed, 76 insertions, 19 deletions
diff --git a/lgc.c b/lgc.c
index 347b6778..9973c9db 100644
--- a/lgc.c
+++ b/lgc.c
@@ -859,6 +859,8 @@ static GCObject *udata2finalize (global_State *g) {
859 resetbit(o->marked, FINALIZEDBIT); /* object is "normal" again */ 859 resetbit(o->marked, FINALIZEDBIT); /* object is "normal" again */
860 if (issweepphase(g)) 860 if (issweepphase(g))
861 makewhite(g, o); /* "sweep" object */ 861 makewhite(g, o); /* "sweep" object */
862 else if (getage(o) == G_OLD1)
863 g->firstold1 = o; /* it is the first OLD1 object in the list */
862 return o; 864 return o;
863} 865}
864 866
@@ -957,6 +959,27 @@ static void separatetobefnz (global_State *g, int all) {
957 959
958 960
959/* 961/*
962** If pointer 'p' points to 'o', move it to the next element.
963*/
964static void checkpointer (GCObject **p, GCObject *o) {
965 if (o == *p)
966 *p = o->next;
967}
968
969
970/*
971** Correct pointers to objects inside 'allgc' list when
972** object 'o' is being removed from the list.
973*/
974static void correctpointers (global_State *g, GCObject *o) {
975 checkpointer(&g->survival, o);
976 checkpointer(&g->old1, o);
977 checkpointer(&g->reallyold, o);
978 checkpointer(&g->firstold1, o);
979}
980
981
982/*
960** if object 'o' has a finalizer, remove it from 'allgc' list (must 983** if object 'o' has a finalizer, remove it from 'allgc' list (must
961** search the list to find it) and link it in 'finobj' list. 984** search the list to find it) and link it in 'finobj' list.
962*/ 985*/
@@ -972,14 +995,8 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
972 if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ 995 if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */
973 g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */ 996 g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */
974 } 997 }
975 else { /* correct pointers into 'allgc' list, if needed */ 998 else
976 if (o == g->survival) 999 correctpointers(g, o);
977 g->survival = o->next;
978 if (o == g->old1)
979 g->old1 = o->next;
980 if (o == g->reallyold)
981 g->reallyold = o->next;
982 }
983 /* search for pointer pointing to 'o' */ 1000 /* search for pointer pointing to 'o' */
984 for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } 1001 for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ }
985 *p = o->next; /* remove 'o' from 'allgc' list */ 1002 *p = o->next; /* remove 'o' from 'allgc' list */
@@ -1033,7 +1050,7 @@ static void sweep2old (lua_State *L, GCObject **p) {
1033** will also remove objects turned white here from any gray list. 1050** will also remove objects turned white here from any gray list.
1034*/ 1051*/
1035static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, 1052static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
1036 GCObject *limit) { 1053 GCObject *limit, GCObject **pfirstold1) {
1037 static const lu_byte nextage[] = { 1054 static const lu_byte nextage[] = {
1038 G_SURVIVAL, /* from G_NEW */ 1055 G_SURVIVAL, /* from G_NEW */
1039 G_OLD1, /* from G_SURVIVAL */ 1056 G_OLD1, /* from G_SURVIVAL */
@@ -1056,8 +1073,11 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
1056 int marked = curr->marked & maskgcbits; /* erase GC bits */ 1073 int marked = curr->marked & maskgcbits; /* erase GC bits */
1057 curr->marked = cast_byte(marked | G_SURVIVAL | white); 1074 curr->marked = cast_byte(marked | G_SURVIVAL | white);
1058 } 1075 }
1059 else /* all other objects will be old, and so keep their color */ 1076 else { /* all other objects will be old, and so keep their color */
1060 setage(curr, nextage[getage(curr)]); 1077 setage(curr, nextage[getage(curr)]);
1078 if (getage(curr) == G_OLD1 && *pfirstold1 == NULL)
1079 *pfirstold1 = curr; /* first OLD1 object in the list */
1080 }
1061 p = &curr->next; /* go to next element */ 1081 p = &curr->next; /* go to next element */
1062 } 1082 }
1063 } 1083 }
@@ -1169,30 +1189,34 @@ static void finishgencycle (lua_State *L, global_State *g) {
1169*/ 1189*/
1170static void youngcollection (lua_State *L, global_State *g) { 1190static void youngcollection (lua_State *L, global_State *g) {
1171 GCObject **psurvival; /* to point to first non-dead survival object */ 1191 GCObject **psurvival; /* to point to first non-dead survival object */
1192 GCObject *dummy; /* dummy out parameter to 'sweepgen' */
1172 lua_assert(g->gcstate == GCSpropagate); 1193 lua_assert(g->gcstate == GCSpropagate);
1173 markold(g, g->allgc, g->reallyold); 1194 if (g->firstold1) { /* are there OLD1 objects? */
1195 markold(g, g->firstold1, g->reallyold); /* mark them */
1196 g->firstold1 = NULL; /* no more OLD1 objects (for now) */
1197 }
1174 markold(g, g->finobj, g->finobjrold); 1198 markold(g, g->finobj, g->finobjrold);
1175 atomic(L); 1199 atomic(L);
1176 1200
1177 /* sweep nursery and get a pointer to its last live element */ 1201 /* sweep nursery and get a pointer to its last live element */
1178 g->gcstate = GCSswpallgc; 1202 g->gcstate = GCSswpallgc;
1179 psurvival = sweepgen(L, g, &g->allgc, g->survival); 1203 psurvival = sweepgen(L, g, &g->allgc, g->survival, &g->firstold1);
1180 /* sweep 'survival' */ 1204 /* sweep 'survival' */
1181 sweepgen(L, g, psurvival, g->old1); 1205 sweepgen(L, g, psurvival, g->old1, &g->firstold1);
1182 g->reallyold = g->old1; 1206 g->reallyold = g->old1;
1183 g->old1 = *psurvival; /* 'survival' survivals are old now */ 1207 g->old1 = *psurvival; /* 'survival' survivals are old now */
1184 g->survival = g->allgc; /* all news are survivals */ 1208 g->survival = g->allgc; /* all news are survivals */
1185 1209
1186 /* repeat for 'finobj' lists */ 1210 /* repeat for 'finobj' lists */
1187 psurvival = sweepgen(L, g, &g->finobj, g->finobjsur); 1211 dummy = NULL; /* no 'firstold1' optimization for 'finobj' lists */
1212 psurvival = sweepgen(L, g, &g->finobj, g->finobjsur, &dummy);
1188 /* sweep 'survival' */ 1213 /* sweep 'survival' */
1189 sweepgen(L, g, psurvival, g->finobjold1); 1214 sweepgen(L, g, psurvival, g->finobjold1, &dummy);
1190 g->finobjrold = g->finobjold1; 1215 g->finobjrold = g->finobjold1;
1191 g->finobjold1 = *psurvival; /* 'survival' survivals are old now */ 1216 g->finobjold1 = *psurvival; /* 'survival' survivals are old now */
1192 g->finobjsur = g->finobj; /* all news are survivals */ 1217 g->finobjsur = g->finobj; /* all news are survivals */
1193 1218
1194 sweepgen(L, g, &g->tobefnz, NULL); 1219 sweepgen(L, g, &g->tobefnz, NULL, &dummy);
1195
1196 finishgencycle(L, g); 1220 finishgencycle(L, g);
1197} 1221}
1198 1222
@@ -1203,6 +1227,7 @@ static void atomic2gen (lua_State *L, global_State *g) {
1203 sweep2old(L, &g->allgc); 1227 sweep2old(L, &g->allgc);
1204 /* everything alive now is old */ 1228 /* everything alive now is old */
1205 g->reallyold = g->old1 = g->survival = g->allgc; 1229 g->reallyold = g->old1 = g->survival = g->allgc;
1230 g->firstold1 = NULL; /* there are no OLD1 objects anywhere */
1206 1231
1207 /* repeat for 'finobj' lists */ 1232 /* repeat for 'finobj' lists */
1208 sweep2old(L, &g->finobj); 1233 sweep2old(L, &g->finobj);
diff --git a/lstate.c b/lstate.c
index 38a2b45a..86b3761f 100644
--- a/lstate.c
+++ b/lstate.c
@@ -413,7 +413,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
413 g->gckind = KGC_INC; 413 g->gckind = KGC_INC;
414 g->gcemergency = 0; 414 g->gcemergency = 0;
415 g->finobj = g->tobefnz = g->fixedgc = NULL; 415 g->finobj = g->tobefnz = g->fixedgc = NULL;
416 g->survival = g->old1 = g->reallyold = NULL; 416 g->firstold1 = g->survival = g->old1 = g->reallyold = NULL;
417 g->finobjsur = g->finobjold1 = g->finobjrold = NULL; 417 g->finobjsur = g->finobjold1 = g->finobjrold = NULL;
418 g->sweepgc = NULL; 418 g->sweepgc = NULL;
419 g->gray = g->grayagain = NULL; 419 g->gray = g->grayagain = NULL;
diff --git a/lstate.h b/lstate.h
index c02b4c8b..697d73b2 100644
--- a/lstate.h
+++ b/lstate.h
@@ -46,6 +46,15 @@
46** lists. Moreover, barriers can age young objects in young lists as 46** lists. Moreover, barriers can age young objects in young lists as
47** OLD0, which then become OLD1. However, a list never contains 47** OLD0, which then become OLD1. However, a list never contains
48** elements younger than their main ages. 48** elements younger than their main ages.
49**
50** The generational collector also uses a pointer 'firstold1', which
51** points to the first OLD1 object in the list. It is used to optimize
52** 'markold'. (Potentially OLD1 objects can be anywhere between 'allgc'
53** and 'reallyold', but often the list has no OLD1 objects or they are
54** after 'old1'.) Note the difference between it and 'old1':
55** 'firstold1': no OLD1 objects before this point; there can be all
56** ages after it.
57** 'old1': no objects younger than OLD1 after this point.
49*/ 58*/
50 59
51/* 60/*
@@ -54,7 +63,7 @@
54** can become gray have such a field. The field is not the same 63** can become gray have such a field. The field is not the same
55** in all objects, but it always has this name.) Any gray object 64** in all objects, but it always has this name.) Any gray object
56** must belong to one of these lists, and all objects in these lists 65** must belong to one of these lists, and all objects in these lists
57** must be gray: 66** must be gray (with one exception explained below):
58** 67**
59** 'gray': regular gray objects, still waiting to be visited. 68** 'gray': regular gray objects, still waiting to be visited.
60** 'grayagain': objects that must be revisited at the atomic phase. 69** 'grayagain': objects that must be revisited at the atomic phase.
@@ -65,6 +74,12 @@
65** 'weak': tables with weak values to be cleared; 74** 'weak': tables with weak values to be cleared;
66** 'ephemeron': ephemeron tables with white->white entries; 75** 'ephemeron': ephemeron tables with white->white entries;
67** 'allweak': tables with weak keys and/or weak values to be cleared. 76** 'allweak': tables with weak keys and/or weak values to be cleared.
77**
78** The exception to that "gray rule" is the TOUCHED2 objects in
79** generational mode. Those objects stay in a gray list (because they
80** must be visited again at the end of the cycle), but they are marked
81** black (because assignments to them must activate barriers, to move
82** them back to TOUCHED1).
68*/ 83*/
69 84
70 85
@@ -266,6 +281,7 @@ typedef struct global_State {
266 GCObject *survival; /* start of objects that survived one GC cycle */ 281 GCObject *survival; /* start of objects that survived one GC cycle */
267 GCObject *old1; /* start of old1 objects */ 282 GCObject *old1; /* start of old1 objects */
268 GCObject *reallyold; /* objects more than one cycle old ("really old") */ 283 GCObject *reallyold; /* objects more than one cycle old ("really old") */
284 GCObject *firstold1; /* first OLD1 object in the list (if any) */
269 GCObject *finobjsur; /* list of survival objects with finalizers */ 285 GCObject *finobjsur; /* list of survival objects with finalizers */
270 GCObject *finobjold1; /* list of old1 objects with finalizers */ 286 GCObject *finobjold1; /* list of old1 objects with finalizers */
271 GCObject *finobjrold; /* list of really old objects with finalizers */ 287 GCObject *finobjrold; /* list of really old objects with finalizers */
diff --git a/testes/gengc.lua b/testes/gengc.lua
index 7a7dabdd..93b5afd7 100644
--- a/testes/gengc.lua
+++ b/testes/gengc.lua
@@ -37,6 +37,22 @@ do
37end 37end
38 38
39 39
40do
41 -- ensure that 'firstold1' is corrected when object is removed from
42 -- the 'allgc' list
43 local function foo () end
44 local old = {10}
45 collectgarbage() -- make 'old' old
46 assert(not T or T.gcage(old) == "old")
47 setmetatable(old, {}) -- new table becomes OLD0 (barrier)
48 assert(not T or T.gcage(getmetatable(old)) == "old0")
49 collectgarbage("step", 0) -- new table becomes OLD1 and firstold1
50 assert(not T or T.gcage(getmetatable(old)) == "old1")
51 setmetatable(getmetatable(old), {__gc = foo}) -- get it out of allgc list
52 collectgarbage("step", 0) -- should not seg. fault
53end
54
55
40do -- bug in 5.4.0 56do -- bug in 5.4.0
41-- When an object aged OLD1 is finalized, it is moved from the list 57-- When an object aged OLD1 is finalized, it is moved from the list
42-- 'finobj' to the *beginning* of the list 'allgc', but that part of the 58-- 'finobj' to the *beginning* of the list 'allgc', but that part of the