aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2023-11-29 16:22:09 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2023-11-29 16:22:09 -0300
commit63d68bd657b7386c9c58b4439a100ea0ccbd633e (patch)
tree117ae53a7b1cbfd242370af0c5250fca85fd2a7d
parent011850a8f86f514d1ba2ebf7a9411c8036b917f4 (diff)
downloadlua-63d68bd657b7386c9c58b4439a100ea0ccbd633e.tar.gz
lua-63d68bd657b7386c9c58b4439a100ea0ccbd633e.tar.bz2
lua-63d68bd657b7386c9c58b4439a100ea0ccbd633e.zip
Comments detailing the ages for generational GC
Plus other comments and small details.
-rw-r--r--lauxlib.c5
-rw-r--r--lgc.c11
-rw-r--r--lgc.h44
-rw-r--r--lstate.c5
-rw-r--r--ltests.c10
5 files changed, 59 insertions, 16 deletions
diff --git a/lauxlib.c b/lauxlib.c
index 927e36f0..ab3c7c93 100644
--- a/lauxlib.c
+++ b/lauxlib.c
@@ -1139,12 +1139,11 @@ static unsigned int luai_makeseed (void) {
1139 unsigned int res; 1139 unsigned int res;
1140 unsigned int i; 1140 unsigned int i;
1141 time_t t = time(NULL); 1141 time_t t = time(NULL);
1142 void *h = buff;
1143 char *b = (char*)buff; 1142 char *b = (char*)buff;
1144 addbuff(b, h); /* local variable's address */ 1143 addbuff(b, b); /* local variable's address */
1145 addbuff(b, t); /* time */ 1144 addbuff(b, t); /* time */
1146 /* fill (rare but possible) remain of the buffer with zeros */ 1145 /* fill (rare but possible) remain of the buffer with zeros */
1147 memset(b, 0, BUFSEED * sizeof(int) - BUFSEEDB); 1146 memset(b, 0, sizeof(buff) - BUFSEEDB);
1148 res = buff[0]; 1147 res = buff[0];
1149 for (i = 0; i < BUFSEED; i++) 1148 for (i = 0; i < BUFSEED; i++)
1150 res ^= (res >> 3) + (res << 7) + buff[i]; 1149 res ^= (res >> 3) + (res << 7) + buff[i];
diff --git a/lgc.c b/lgc.c
index 3884aad0..daee5707 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1121,6 +1121,7 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
1121 curr->marked = cast_byte(marked | G_SURVIVAL | white); 1121 curr->marked = cast_byte(marked | G_SURVIVAL | white);
1122 } 1122 }
1123 else { /* all other objects will be old, and so keep their color */ 1123 else { /* all other objects will be old, and so keep their color */
1124 lua_assert(getage(curr) != G_OLD1); /* advanced in 'markold' */
1124 setage(curr, nextage[getage(curr)]); 1125 setage(curr, nextage[getage(curr)]);
1125 if (getage(curr) == G_OLD1 && *pfirstold1 == NULL) 1126 if (getage(curr) == G_OLD1 && *pfirstold1 == NULL)
1126 *pfirstold1 = curr; /* first OLD1 object in the list */ 1127 *pfirstold1 = curr; /* first OLD1 object in the list */
@@ -1145,13 +1146,15 @@ static void whitelist (global_State *g, GCObject *p) {
1145 1146
1146 1147
1147/* 1148/*
1148** Correct a list of gray objects. Return pointer to where rest of the 1149** Correct a list of gray objects. Return a pointer to the last element
1149** list should be linked. 1150** left on the list, so that we can link another list to the end of
1151** this one.
1150** Because this correction is done after sweeping, young objects might 1152** Because this correction is done after sweeping, young objects might
1151** be turned white and still be in the list. They are only removed. 1153** be turned white and still be in the list. They are only removed.
1152** 'TOUCHED1' objects are advanced to 'TOUCHED2' and remain on the list; 1154** 'TOUCHED1' objects are advanced to 'TOUCHED2' and remain on the list;
1153** Non-white threads also remain on the list; 'TOUCHED2' objects become 1155** Non-white threads also remain on the list. 'TOUCHED2' objects and
1154** regular old; they and anything else are removed from the list. 1156** anything else become regular old, are marked black, and are removed
1157** from the list.
1155*/ 1158*/
1156static GCObject **correctgraylist (GCObject **p) { 1159static GCObject **correctgraylist (GCObject **p) {
1157 GCObject *curr; 1160 GCObject *curr;
diff --git a/lgc.h b/lgc.h
index 959465ec..f06427c2 100644
--- a/lgc.h
+++ b/lgc.h
@@ -123,6 +123,43 @@
123#define changeage(o,f,t) \ 123#define changeage(o,f,t) \
124 check_exp(getage(o) == (f), (o)->marked ^= ((f)^(t))) 124 check_exp(getage(o) == (f), (o)->marked ^= ((f)^(t)))
125 125
126/*
127** In generational mode, objects are created 'new'. After surviving one
128** cycle, they become 'survival'. Both 'new' and 'survival' can point
129** to any other object, as they are traversed at the end of the cycle.
130** We call them both 'young' objects.
131** If a survival object survives another cycle, it becomes 'old1'.
132** 'old1' objects can still point to survival objects (but not to
133** new objects), so they still must be traversed. After another cycle
134** (that, being old, 'old1' objects will "survive" no matter what)
135** finally the 'old1' object becomes really 'old', and then they
136** are no more traversed.
137**
138** To keep its invariants, the generational mode uses the same barriers
139** also used by the incremental mode. If a young object is caught in a
140** foward barrier, it cannot become old immediately, because it can
141** still point to other young objects. Instead, it becomes 'old0',
142** which in the next cycle becomes 'old1'. So, 'old0' objects is
143** old but can point to new and survival objects; 'old1' is old
144** but cannot point to new objects; and 'old' cannot point to any
145** young object.
146**
147** If any old object ('old0', 'old1', 'old') is caught in a back
148** barrier, it becomes 'touched1' and goes into a gray list, to be
149** visited at the end of the cycle. There it evolves to 'touched2',
150** which can point to survivals but not to new objects. In yet another
151** cycle then it becomes 'old' again.
152**
153** The generational mode must also control the colors of objects,
154** because of the barriers. While the mutator is running, young objects
155** are kept white. 'old', 'old1', and 'touched2' objects are kept black,
156** as they cannot point to new objects; exceptions are threads and open
157** upvalues, which age to 'old1' and 'old' but are kept gray. 'old0'
158** objects may be gray or black, as in the incremental mode. 'touched1'
159** objects are kept gray, as they must be visited again at the end of
160** the cycle.
161*/
162
126 163
127/* Default Values for GC parameters */ 164/* Default Values for GC parameters */
128 165
@@ -161,9 +198,10 @@
161** (value * original parameter / 100). 198** (value * original parameter / 100).
162** 199**
163** For most parameters, which are typically larger than 100%, 2^n is 200** For most parameters, which are typically larger than 100%, 2^n is
164** 16 (2^4), allowing maximum values up to 1599. For the minor 201** 16 (2^4), allowing maximum values up to ~1500%, with a granularity
165** multiplier, which is typically smaller, 2^n is 64 (2^6) to allow more 202** of ~6%. For the minor multiplier, which is typically smaller,
166** precision. 203** 2^n is 64 (2^6) to allow more precision. In that case, the maximum
204** value is ~400%, with a granularity of ~1.5%.
167*/ 205*/
168#define gcparamshift(p) \ 206#define gcparamshift(p) \
169 (offsetof(global_State, p) == offsetof(global_State, genminormul) ? 6 : 4) 207 (offsetof(global_State, p) == offsetof(global_State, genminormul) ? 6 : 4)
diff --git a/lstate.c b/lstate.c
index c01e53ed..1216db35 100644
--- a/lstate.c
+++ b/lstate.c
@@ -52,8 +52,9 @@ typedef struct LG {
52 52
53 53
54/* 54/*
55** set GCdebt to a new value keeping the value (totalobjs + GCdebt) 55** set GCdebt to a new value keeping the real number of allocated
56** invariant (and avoiding underflows in 'totalobjs') 56** objects (totalobjs - GCdebt) invariant and avoiding overflows in
57** 'totalobjs'.
57*/ 58*/
58void luaE_setdebt (global_State *g, l_obj debt) { 59void luaE_setdebt (global_State *g, l_obj debt) {
59 l_obj tb = gettotalobjs(g); 60 l_obj tb = gettotalobjs(g);
diff --git a/ltests.c b/ltests.c
index bd4147f2..09c2e030 100644
--- a/ltests.c
+++ b/ltests.c
@@ -302,8 +302,8 @@ static int testobjref1 (global_State *g, GCObject *f, GCObject *t) {
302 else { /* generational mode */ 302 else { /* generational mode */
303 if ((getage(f) == G_OLD && isblack(f)) && !isold(t)) 303 if ((getage(f) == G_OLD && isblack(f)) && !isold(t))
304 return 0; 304 return 0;
305 if (((getage(f) == G_OLD1 || getage(f) == G_TOUCHED2) && isblack(f)) && 305 if ((getage(f) == G_OLD1 || getage(f) == G_TOUCHED2) &&
306 getage(t) == G_NEW) 306 getage(t) == G_NEW)
307 return 0; 307 return 0;
308 return 1; 308 return 1;
309 } 309 }
@@ -510,7 +510,8 @@ static void checkrefs (global_State *g, GCObject *o) {
510** * objects must be old enough for their lists ('listage'). 510** * objects must be old enough for their lists ('listage').
511** * old objects cannot be white. 511** * old objects cannot be white.
512** * old objects must be black, except for 'touched1', 'old0', 512** * old objects must be black, except for 'touched1', 'old0',
513** threads, and open upvalues. 513** threads, and open upvalues.
514** * 'touched1' objects must be gray.
514*/ 515*/
515static void checkobject (global_State *g, GCObject *o, int maybedead, 516static void checkobject (global_State *g, GCObject *o, int maybedead,
516 int listage) { 517 int listage) {
@@ -520,14 +521,15 @@ static void checkobject (global_State *g, GCObject *o, int maybedead,
520 assert(g->gcstate != GCSpause || iswhite(o)); 521 assert(g->gcstate != GCSpause || iswhite(o));
521 if (g->gckind == KGC_GEN) { /* generational mode? */ 522 if (g->gckind == KGC_GEN) { /* generational mode? */
522 assert(getage(o) >= listage); 523 assert(getage(o) >= listage);
523 assert(!iswhite(o) || !isold(o));
524 if (isold(o)) { 524 if (isold(o)) {
525 assert(!iswhite(o));
525 assert(isblack(o) || 526 assert(isblack(o) ||
526 getage(o) == G_TOUCHED1 || 527 getage(o) == G_TOUCHED1 ||
527 getage(o) == G_OLD0 || 528 getage(o) == G_OLD0 ||
528 o->tt == LUA_VTHREAD || 529 o->tt == LUA_VTHREAD ||
529 (o->tt == LUA_VUPVAL && upisopen(gco2upv(o)))); 530 (o->tt == LUA_VUPVAL && upisopen(gco2upv(o))));
530 } 531 }
532 assert(getage(o) != G_TOUCHED1 || isgray(o));
531 } 533 }
532 checkrefs(g, o); 534 checkrefs(g, o);
533 } 535 }