aboutsummaryrefslogtreecommitdiff
path: root/src/lua/lgc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lua/lgc.c')
-rw-r--r--src/lua/lgc.c349
1 files changed, 220 insertions, 129 deletions
diff --git a/src/lua/lgc.c b/src/lua/lgc.c
index f7fd7a5..cb820f9 100644
--- a/src/lua/lgc.c
+++ b/src/lua/lgc.c
@@ -60,13 +60,16 @@
60#define PAUSEADJ 100 60#define PAUSEADJ 100
61 61
62 62
63/* mask to erase all color bits (plus gen. related stuff) */ 63/* mask to erase all color bits */
64#define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS | AGEBITS)) 64#define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS))
65 65
66/* mask to erase all GC bits */
67#define maskgcbits (maskcolors & ~AGEBITS)
66 68
67/* macro to erase all color bits then sets only the current white bit */ 69
70/* macro to erase all color bits then set only the current white bit */
68#define makewhite(g,x) \ 71#define makewhite(g,x) \
69 (x->marked = cast_byte((x->marked & maskcolors) | luaC_white(g))) 72 (x->marked = cast_byte((x->marked & maskcolors) | luaC_white(g)))
70 73
71#define white2gray(x) resetbits(x->marked, WHITEBITS) 74#define white2gray(x) resetbits(x->marked, WHITEBITS)
72#define black2gray(x) resetbit(x->marked, BLACKBIT) 75#define black2gray(x) resetbit(x->marked, BLACKBIT)
@@ -77,16 +80,13 @@
77#define keyiswhite(n) (keyiscollectable(n) && iswhite(gckey(n))) 80#define keyiswhite(n) (keyiscollectable(n) && iswhite(gckey(n)))
78 81
79 82
80#define checkconsistency(obj) \
81 lua_longassert(!iscollectable(obj) || righttt(obj))
82
83/* 83/*
84** Protected access to objects in values 84** Protected access to objects in values
85*/ 85*/
86#define gcvalueN(o) (iscollectable(o) ? gcvalue(o) : NULL) 86#define gcvalueN(o) (iscollectable(o) ? gcvalue(o) : NULL)
87 87
88 88
89#define markvalue(g,o) { checkconsistency(o); \ 89#define markvalue(g,o) { checkliveness(g->mainthread,o); \
90 if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } 90 if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); }
91 91
92#define markkey(g, n) { if keyiswhite(n) reallymarkobject(g,gckey(n)); } 92#define markkey(g, n) { if keyiswhite(n) reallymarkobject(g,gckey(n)); }
@@ -181,14 +181,17 @@ static int iscleared (global_State *g, const GCObject *o) {
181 181
182 182
183/* 183/*
184** barrier that moves collector forward, that is, mark the white object 184** Barrier that moves collector forward, that is, marks the white object
185** 'v' being pointed by the black object 'o'. (If in sweep phase, clear 185** 'v' being pointed by the black object 'o'. In the generational
186** the black object to white [sweep it] to avoid other barrier calls for 186** mode, 'v' must also become old, if 'o' is old; however, it cannot
187** this same object.) In the generational mode, 'v' must also become 187** be changed directly to OLD, because it may still point to non-old
188** old, if 'o' is old; however, it cannot be changed directly to OLD, 188** objects. So, it is marked as OLD0. In the next cycle it will become
189** because it may still point to non-old objects. So, it is marked as 189** OLD1, and in the next it will finally become OLD (regular old). By
190** OLD0. In the next cycle it will become OLD1, and in the next it 190** then, any object it points to will also be old. If called in the
191** will finally become OLD (regular old). 191** incremental sweep phase, it clears the black object to white (sweep
192** it) to avoid other barrier calls for this same object. (That cannot
193** be done is generational mode, as its sweep does not distinguish
194** whites from deads.)
192*/ 195*/
193void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { 196void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
194 global_State *g = G(L); 197 global_State *g = G(L);
@@ -202,7 +205,8 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
202 } 205 }
203 else { /* sweep phase */ 206 else { /* sweep phase */
204 lua_assert(issweepphase(g)); 207 lua_assert(issweepphase(g));
205 makewhite(g, o); /* mark main obj. as white to avoid other barriers */ 208 if (g->gckind == KGC_INC) /* incremental mode? */
209 makewhite(g, o); /* mark 'o' as white to avoid other barriers */
206 } 210 }
207} 211}
208 212
@@ -214,11 +218,12 @@ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) {
214void luaC_barrierback_ (lua_State *L, GCObject *o) { 218void luaC_barrierback_ (lua_State *L, GCObject *o) {
215 global_State *g = G(L); 219 global_State *g = G(L);
216 lua_assert(isblack(o) && !isdead(g, o)); 220 lua_assert(isblack(o) && !isdead(g, o));
217 lua_assert(g->gckind != KGC_GEN || (isold(o) && getage(o) != G_TOUCHED1)); 221 lua_assert((g->gckind == KGC_GEN) == (isold(o) && getage(o) != G_TOUCHED1));
218 if (getage(o) != G_TOUCHED2) /* not already in gray list? */ 222 if (getage(o) != G_TOUCHED2) /* not already in gray list? */
219 linkobjgclist(o, g->grayagain); /* link it in 'grayagain' */ 223 linkobjgclist(o, g->grayagain); /* link it in 'grayagain' */
220 black2gray(o); /* make object gray (again) */ 224 black2gray(o); /* make object gray (again) */
221 setage(o, G_TOUCHED1); /* touched in current cycle */ 225 if (isold(o)) /* generational mode? */
226 setage(o, G_TOUCHED1); /* touched in current cycle */
222} 227}
223 228
224 229
@@ -324,25 +329,31 @@ static lu_mem markbeingfnz (global_State *g) {
324 329
325 330
326/* 331/*
327** Mark all values stored in marked open upvalues from non-marked threads. 332** For each non-marked thread, simulates a barrier between each open
328** (Values from marked threads were already marked when traversing the 333** upvalue and its value. (If the thread is collected, the value will be
329** thread.) Remove from the list threads that no longer have upvalues and 334** assigned to the upvalue, but then it can be too late for the barrier
330** not-marked threads. 335** to act. The "barrier" does not need to check colors: A non-marked
336** thread must be young; upvalues cannot be older than their threads; so
337** any visited upvalue must be young too.) Also removes the thread from
338** the list, as it was already visited. Removes also threads with no
339** upvalues, as they have nothing to be checked. (If the thread gets an
340** upvalue later, it will be linked in the list again.)
331*/ 341*/
332static int remarkupvals (global_State *g) { 342static int remarkupvals (global_State *g) {
333 lua_State *thread; 343 lua_State *thread;
334 lua_State **p = &g->twups; 344 lua_State **p = &g->twups;
335 int work = 0; 345 int work = 0; /* estimate of how much work was done here */
336 while ((thread = *p) != NULL) { 346 while ((thread = *p) != NULL) {
337 work++; 347 work++;
338 lua_assert(!isblack(thread)); /* threads are never black */ 348 if (!iswhite(thread) && thread->openupval != NULL)
339 if (isgray(thread) && thread->openupval != NULL)
340 p = &thread->twups; /* keep marked thread with upvalues in the list */ 349 p = &thread->twups; /* keep marked thread with upvalues in the list */
341 else { /* thread is not marked or without upvalues */ 350 else { /* thread is not marked or without upvalues */
342 UpVal *uv; 351 UpVal *uv;
352 lua_assert(!isold(thread) || thread->openupval == NULL);
343 *p = thread->twups; /* remove thread from the list */ 353 *p = thread->twups; /* remove thread from the list */
344 thread->twups = thread; /* mark that it is out of list */ 354 thread->twups = thread; /* mark that it is out of list */
345 for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { 355 for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) {
356 lua_assert(getage(uv) <= getage(thread));
346 work++; 357 work++;
347 if (!iswhite(uv)) /* upvalue already visited? */ 358 if (!iswhite(uv)) /* upvalue already visited? */
348 markvalue(g, uv->v); /* mark its value */ 359 markvalue(g, uv->v); /* mark its value */
@@ -353,12 +364,17 @@ static int remarkupvals (global_State *g) {
353} 364}
354 365
355 366
367static void cleargraylists (global_State *g) {
368 g->gray = g->grayagain = NULL;
369 g->weak = g->allweak = g->ephemeron = NULL;
370}
371
372
356/* 373/*
357** mark root set and reset all gray lists, to start a new collection 374** mark root set and reset all gray lists, to start a new collection
358*/ 375*/
359static void restartcollection (global_State *g) { 376static void restartcollection (global_State *g) {
360 g->gray = g->grayagain = NULL; 377 cleargraylists(g);
361 g->weak = g->allweak = g->ephemeron = NULL;
362 markobject(g, g->mainthread); 378 markobject(g, g->mainthread);
363 markvalue(g, &g->l_registry); 379 markvalue(g, &g->l_registry);
364 markmt(g); 380 markmt(g);
@@ -374,6 +390,32 @@ static void restartcollection (global_State *g) {
374** ======================================================= 390** =======================================================
375*/ 391*/
376 392
393
394/*
395** Check whether object 'o' should be kept in the 'grayagain' list for
396** post-processing by 'correctgraylist'. (It could put all old objects
397** in the list and leave all the work to 'correctgraylist', but it is
398** more efficient to avoid adding elements that will be removed.) Only
399** TOUCHED1 objects need to be in the list. TOUCHED2 doesn't need to go
400** back to a gray list, but then it must become OLD. (That is what
401** 'correctgraylist' does when it finds a TOUCHED2 object.)
402** It is defined as a macro because 'gclist' is not a unique field in
403** different collectable objects.
404*/
405#define genlink(g,o) genlink_(g, obj2gco(o), &(o)->gclist)
406
407static void genlink_ (global_State *g, GCObject *o, GCObject **pnext) {
408 lua_assert(isblack(o));
409 if (getage(o) == G_TOUCHED1) { /* touched in this cycle? */
410 *pnext = g->grayagain; /* link it back in 'grayagain' */
411 g->grayagain = o;
412 black2gray(o);
413 } /* everything else do not need to be linked back */
414 else if (getage(o) == G_TOUCHED2)
415 changeage(o, G_TOUCHED2, G_OLD); /* advance age */
416}
417
418
377/* 419/*
378** Traverse a table with weak values and link it to proper list. During 420** Traverse a table with weak values and link it to proper list. During
379** propagate phase, keep it in 'grayagain' list, to be revisited in the 421** propagate phase, keep it in 'grayagain' list, to be revisited in the
@@ -410,8 +452,9 @@ static void traverseweakvalue (global_State *g, Table *h) {
410** the atomic phase, if table has any white->white entry, it has to 452** the atomic phase, if table has any white->white entry, it has to
411** be revisited during ephemeron convergence (as that key may turn 453** be revisited during ephemeron convergence (as that key may turn
412** black). Otherwise, if it has any white key, table has to be cleared 454** black). Otherwise, if it has any white key, table has to be cleared
413** (in the atomic phase). In generational mode, it (like all visited 455** (in the atomic phase). In generational mode, some tables
414** tables) must be kept in some gray list for post-processing. 456** must be kept in some gray list for post-processing; this is done
457** by 'genlink'.
415*/ 458*/
416static int traverseephemeron (global_State *g, Table *h, int inv) { 459static int traverseephemeron (global_State *g, Table *h, int inv) {
417 int marked = 0; /* true if an object is marked in this traversal */ 460 int marked = 0; /* true if an object is marked in this traversal */
@@ -450,10 +493,10 @@ static int traverseephemeron (global_State *g, Table *h, int inv) {
450 linkgclist(h, g->ephemeron); /* have to propagate again */ 493 linkgclist(h, g->ephemeron); /* have to propagate again */
451 else if (hasclears) /* table has white keys? */ 494 else if (hasclears) /* table has white keys? */
452 linkgclist(h, g->allweak); /* may have to clean white keys */ 495 linkgclist(h, g->allweak); /* may have to clean white keys */
453 else if (g->gckind == KGC_GEN) 496 else {
454 linkgclist(h, g->grayagain); /* keep it in some list */ 497 gray2black(h); /* 'genlink' expects black objects */
455 else 498 genlink(g, h); /* check whether collector still needs to see it */
456 gray2black(h); 499 }
457 return marked; 500 return marked;
458} 501}
459 502
@@ -473,10 +516,7 @@ static void traversestrongtable (global_State *g, Table *h) {
473 markvalue(g, gval(n)); 516 markvalue(g, gval(n));
474 } 517 }
475 } 518 }
476 if (g->gckind == KGC_GEN) { 519 genlink(g, h);
477 linkgclist(h, g->grayagain); /* keep it in some gray list */
478 black2gray(h);
479 }
480} 520}
481 521
482 522
@@ -488,7 +528,7 @@ static lu_mem traversetable (global_State *g, Table *h) {
488 (cast_void(weakkey = strchr(svalue(mode), 'k')), 528 (cast_void(weakkey = strchr(svalue(mode), 'k')),
489 cast_void(weakvalue = strchr(svalue(mode), 'v')), 529 cast_void(weakvalue = strchr(svalue(mode), 'v')),
490 (weakkey || weakvalue))) { /* is really weak? */ 530 (weakkey || weakvalue))) { /* is really weak? */
491 black2gray(h); /* keep table gray */ 531 black2gray(h); /* turn it back to gray, as it probably goes to a list */
492 if (!weakkey) /* strong keys? */ 532 if (!weakkey) /* strong keys? */
493 traverseweakvalue(g, h); 533 traverseweakvalue(g, h);
494 else if (!weakvalue) /* strong values? */ 534 else if (!weakvalue) /* strong values? */
@@ -507,10 +547,7 @@ static int traverseudata (global_State *g, Udata *u) {
507 markobjectN(g, u->metatable); /* mark its metatable */ 547 markobjectN(g, u->metatable); /* mark its metatable */
508 for (i = 0; i < u->nuvalue; i++) 548 for (i = 0; i < u->nuvalue; i++)
509 markvalue(g, &u->uv[i].uv); 549 markvalue(g, &u->uv[i].uv);
510 if (g->gckind == KGC_GEN) { 550 genlink(g, u);
511 linkgclist(u, g->grayagain); /* keep it in some gray list */
512 black2gray(u);
513 }
514 return 1 + u->nuvalue; 551 return 1 + u->nuvalue;
515} 552}
516 553
@@ -559,12 +596,23 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
559 596
560/* 597/*
561** Traverse a thread, marking the elements in the stack up to its top 598** Traverse a thread, marking the elements in the stack up to its top
562** and cleaning the rest of the stack in the final traversal. 599** and cleaning the rest of the stack in the final traversal. That
563** That ensures that the entire stack have valid (non-dead) objects. 600** ensures that the entire stack have valid (non-dead) objects.
601** Threads have no barriers. In gen. mode, old threads must be visited
602** at every cycle, because they might point to young objects. In inc.
603** mode, the thread can still be modified before the end of the cycle,
604** and therefore it must be visited again in the atomic phase. To ensure
605** these visits, threads must return to a gray list if they are not new
606** (which can only happen in generational mode) or if the traverse is in
607** the propagate phase (which can only happen in incremental mode).
564*/ 608*/
565static int traversethread (global_State *g, lua_State *th) { 609static int traversethread (global_State *g, lua_State *th) {
566 UpVal *uv; 610 UpVal *uv;
567 StkId o = th->stack; 611 StkId o = th->stack;
612 if (isold(th) || g->gcstate == GCSpropagate) {
613 linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
614 black2gray(th);
615 }
568 if (o == NULL) 616 if (o == NULL)
569 return 1; /* stack not completely built yet */ 617 return 1; /* stack not completely built yet */
570 lua_assert(g->gcstate == GCSatomic || 618 lua_assert(g->gcstate == GCSatomic ||
@@ -603,12 +651,7 @@ static lu_mem propagatemark (global_State *g) {
603 case LUA_VLCL: return traverseLclosure(g, gco2lcl(o)); 651 case LUA_VLCL: return traverseLclosure(g, gco2lcl(o));
604 case LUA_VCCL: return traverseCclosure(g, gco2ccl(o)); 652 case LUA_VCCL: return traverseCclosure(g, gco2ccl(o));
605 case LUA_VPROTO: return traverseproto(g, gco2p(o)); 653 case LUA_VPROTO: return traverseproto(g, gco2p(o));
606 case LUA_VTHREAD: { 654 case LUA_VTHREAD: return traversethread(g, gco2th(o));
607 lua_State *th = gco2th(o);
608 linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
609 black2gray(o);
610 return traversethread(g, th);
611 }
612 default: lua_assert(0); return 0; 655 default: lua_assert(0); return 0;
613 } 656 }
614} 657}
@@ -766,7 +809,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int countin,
766 freeobj(L, curr); /* erase 'curr' */ 809 freeobj(L, curr); /* erase 'curr' */
767 } 810 }
768 else { /* change mark to 'white' */ 811 else { /* change mark to 'white' */
769 curr->marked = cast_byte((marked & maskcolors) | white); 812 curr->marked = cast_byte((marked & maskgcbits) | white);
770 p = &curr->next; /* go to next element */ 813 p = &curr->next; /* go to next element */
771 } 814 }
772 } 815 }
@@ -823,6 +866,8 @@ static GCObject *udata2finalize (global_State *g) {
823 resetbit(o->marked, FINALIZEDBIT); /* object is "normal" again */ 866 resetbit(o->marked, FINALIZEDBIT); /* object is "normal" again */
824 if (issweepphase(g)) 867 if (issweepphase(g))
825 makewhite(g, o); /* "sweep" object */ 868 makewhite(g, o); /* "sweep" object */
869 else if (getage(o) == G_OLD1)
870 g->firstold1 = o; /* it is the first OLD1 object in the list */
826 return o; 871 return o;
827} 872}
828 873
@@ -896,15 +941,15 @@ static GCObject **findlast (GCObject **p) {
896/* 941/*
897** Move all unreachable objects (or 'all' objects) that need 942** Move all unreachable objects (or 'all' objects) that need
898** finalization from list 'finobj' to list 'tobefnz' (to be finalized). 943** finalization from list 'finobj' to list 'tobefnz' (to be finalized).
899** (Note that objects after 'finobjold' cannot be white, so they 944** (Note that objects after 'finobjold1' cannot be white, so they
900** don't need to be traversed. In incremental mode, 'finobjold' is NULL, 945** don't need to be traversed. In incremental mode, 'finobjold1' is NULL,
901** so the whole list is traversed.) 946** so the whole list is traversed.)
902*/ 947*/
903static void separatetobefnz (global_State *g, int all) { 948static void separatetobefnz (global_State *g, int all) {
904 GCObject *curr; 949 GCObject *curr;
905 GCObject **p = &g->finobj; 950 GCObject **p = &g->finobj;
906 GCObject **lastnext = findlast(&g->tobefnz); 951 GCObject **lastnext = findlast(&g->tobefnz);
907 while ((curr = *p) != g->finobjold) { /* traverse all finalizable objects */ 952 while ((curr = *p) != g->finobjold1) { /* traverse all finalizable objects */
908 lua_assert(tofinalize(curr)); 953 lua_assert(tofinalize(curr));
909 if (!(iswhite(curr) || all)) /* not being collected? */ 954 if (!(iswhite(curr) || all)) /* not being collected? */
910 p = &curr->next; /* don't bother with it */ 955 p = &curr->next; /* don't bother with it */
@@ -921,6 +966,27 @@ static void separatetobefnz (global_State *g, int all) {
921 966
922 967
923/* 968/*
969** If pointer 'p' points to 'o', move it to the next element.
970*/
971static void checkpointer (GCObject **p, GCObject *o) {
972 if (o == *p)
973 *p = o->next;
974}
975
976
977/*
978** Correct pointers to objects inside 'allgc' list when
979** object 'o' is being removed from the list.
980*/
981static void correctpointers (global_State *g, GCObject *o) {
982 checkpointer(&g->survival, o);
983 checkpointer(&g->old1, o);
984 checkpointer(&g->reallyold, o);
985 checkpointer(&g->firstold1, o);
986}
987
988
989/*
924** if object 'o' has a finalizer, remove it from 'allgc' list (must 990** if object 'o' has a finalizer, remove it from 'allgc' list (must
925** search the list to find it) and link it in 'finobj' list. 991** search the list to find it) and link it in 'finobj' list.
926*/ 992*/
@@ -936,14 +1002,8 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
936 if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ 1002 if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */
937 g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */ 1003 g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */
938 } 1004 }
939 else { /* correct pointers into 'allgc' list, if needed */ 1005 else
940 if (o == g->survival) 1006 correctpointers(g, o);
941 g->survival = o->next;
942 if (o == g->old)
943 g->old = o->next;
944 if (o == g->reallyold)
945 g->reallyold = o->next;
946 }
947 /* search for pointer pointing to 'o' */ 1007 /* search for pointer pointing to 'o' */
948 for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } 1008 for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ }
949 *p = o->next; /* remove 'o' from 'allgc' list */ 1009 *p = o->next; /* remove 'o' from 'allgc' list */
@@ -965,24 +1025,30 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
965static void setpause (global_State *g); 1025static void setpause (global_State *g);
966 1026
967 1027
968/* mask to erase all color bits, not changing gen-related stuff */
969#define maskgencolors (~(bitmask(BLACKBIT) | WHITEBITS))
970
971
972/* 1028/*
973** Sweep a list of objects, deleting dead ones and turning 1029** Sweep a list of objects to enter generational mode. Deletes dead
974** the non dead to old (without changing their colors). 1030** objects and turns the non dead to old. All non-dead threads---which
1031** are now old---must be in a gray list. Everything else is not in a
1032** gray list.
975*/ 1033*/
976static void sweep2old (lua_State *L, GCObject **p) { 1034static void sweep2old (lua_State *L, GCObject **p) {
977 GCObject *curr; 1035 GCObject *curr;
1036 global_State *g = G(L);
978 while ((curr = *p) != NULL) { 1037 while ((curr = *p) != NULL) {
979 if (iswhite(curr)) { /* is 'curr' dead? */ 1038 if (iswhite(curr)) { /* is 'curr' dead? */
980 lua_assert(isdead(G(L), curr)); 1039 lua_assert(isdead(g, curr));
981 *p = curr->next; /* remove 'curr' from list */ 1040 *p = curr->next; /* remove 'curr' from list */
982 freeobj(L, curr); /* erase 'curr' */ 1041 freeobj(L, curr); /* erase 'curr' */
983 } 1042 }
984 else { /* all surviving objects become old */ 1043 else { /* all surviving objects become old */
985 setage(curr, G_OLD); 1044 setage(curr, G_OLD);
1045 if (curr->tt == LUA_VTHREAD) { /* threads must be watched */
1046 lua_State *th = gco2th(curr);
1047 linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
1048 black2gray(th); /* OK if already gray */
1049 }
1050 else /* everything else is black */
1051 gray2black(curr); /* OK if already black */
986 p = &curr->next; /* go to next element */ 1052 p = &curr->next; /* go to next element */
987 } 1053 }
988 } 1054 }
@@ -995,9 +1061,13 @@ static void sweep2old (lua_State *L, GCObject **p) {
995** during the sweep. So, any white object must be dead.) For 1061** during the sweep. So, any white object must be dead.) For
996** non-dead objects, advance their ages and clear the color of 1062** non-dead objects, advance their ages and clear the color of
997** new objects. (Old objects keep their colors.) 1063** new objects. (Old objects keep their colors.)
1064** The ages of G_TOUCHED1 and G_TOUCHED2 objects cannot be advanced
1065** here, because these old-generation objects are usually not swept
1066** here. They will all be advanced in 'correctgraylist'. That function
1067** will also remove objects turned white here from any gray list.
998*/ 1068*/
999static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, 1069static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
1000 GCObject *limit) { 1070 GCObject *limit, GCObject **pfirstold1) {
1001 static const lu_byte nextage[] = { 1071 static const lu_byte nextage[] = {
1002 G_SURVIVAL, /* from G_NEW */ 1072 G_SURVIVAL, /* from G_NEW */
1003 G_OLD1, /* from G_SURVIVAL */ 1073 G_OLD1, /* from G_SURVIVAL */
@@ -1016,9 +1086,15 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
1016 freeobj(L, curr); /* erase 'curr' */ 1086 freeobj(L, curr); /* erase 'curr' */
1017 } 1087 }
1018 else { /* correct mark and age */ 1088 else { /* correct mark and age */
1019 if (getage(curr) == G_NEW) 1089 if (getage(curr) == G_NEW) { /* new objects go back to white */
1020 curr->marked = cast_byte((curr->marked & maskgencolors) | white); 1090 int marked = curr->marked & maskgcbits; /* erase GC bits */
1021 setage(curr, nextage[getage(curr)]); 1091 curr->marked = cast_byte(marked | G_SURVIVAL | white);
1092 }
1093 else { /* all other objects will be old, and so keep their color */
1094 setage(curr, nextage[getage(curr)]);
1095 if (getage(curr) == G_OLD1 && *pfirstold1 == NULL)
1096 *pfirstold1 = curr; /* first OLD1 object in the list */
1097 }
1022 p = &curr->next; /* go to next element */ 1098 p = &curr->next; /* go to next element */
1023 } 1099 }
1024 } 1100 }
@@ -1028,58 +1104,56 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p,
1028 1104
1029/* 1105/*
1030** Traverse a list making all its elements white and clearing their 1106** Traverse a list making all its elements white and clearing their
1031** age. 1107** age. In incremental mode, all objects are 'new' all the time,
1108** except for fixed strings (which are always old).
1032*/ 1109*/
1033static void whitelist (global_State *g, GCObject *p) { 1110static void whitelist (global_State *g, GCObject *p) {
1034 int white = luaC_white(g); 1111 int white = luaC_white(g);
1035 for (; p != NULL; p = p->next) 1112 for (; p != NULL; p = p->next)
1036 p->marked = cast_byte((p->marked & maskcolors) | white); 1113 p->marked = cast_byte((p->marked & maskgcbits) | white);
1037} 1114}
1038 1115
1039 1116
1040/* 1117/*
1041** Correct a list of gray objects. 1118** Correct a list of gray objects. Return pointer to where rest of the
1119** list should be linked.
1042** Because this correction is done after sweeping, young objects might 1120** Because this correction is done after sweeping, young objects might
1043** be turned white and still be in the list. They are only removed. 1121** be turned white and still be in the list. They are only removed.
1044** For tables and userdata, advance 'touched1' to 'touched2'; 'touched2' 1122** 'TOUCHED1' objects are advanced to 'TOUCHED2' and remain on the list;
1045** objects become regular old and are removed from the list. 1123** Non-white threads also remain on the list; 'TOUCHED2' objects become
1046** For threads, just remove white ones from the list. 1124** regular old; they and anything else are removed from the list.
1047*/ 1125*/
1048static GCObject **correctgraylist (GCObject **p) { 1126static GCObject **correctgraylist (GCObject **p) {
1049 GCObject *curr; 1127 GCObject *curr;
1050 while ((curr = *p) != NULL) { 1128 while ((curr = *p) != NULL) {
1051 switch (curr->tt) { 1129 GCObject **next = getgclist(curr);
1052 case LUA_VTABLE: case LUA_VUSERDATA: { 1130 if (iswhite(curr))
1053 GCObject **next = getgclist(curr); 1131 goto remove; /* remove all white objects */
1054 if (getage(curr) == G_TOUCHED1) { /* touched in this cycle? */ 1132 else if (getage(curr) == G_TOUCHED1) { /* touched in this cycle? */
1055 lua_assert(isgray(curr)); 1133 lua_assert(isgray(curr));
1056 gray2black(curr); /* make it black, for next barrier */ 1134 gray2black(curr); /* make it black, for next barrier */
1057 changeage(curr, G_TOUCHED1, G_TOUCHED2); 1135 changeage(curr, G_TOUCHED1, G_TOUCHED2);
1058 p = next; /* go to next element */ 1136 goto remain; /* keep it in the list and go to next element */
1059 } 1137 }
1060 else { /* not touched in this cycle */ 1138 else if (curr->tt == LUA_VTHREAD) {
1061 if (!iswhite(curr)) { /* not white? */ 1139 lua_assert(isgray(curr));
1062 lua_assert(isold(curr)); 1140 goto remain; /* keep non-white threads on the list */
1063 if (getage(curr) == G_TOUCHED2) /* advance from G_TOUCHED2... */ 1141 }
1064 changeage(curr, G_TOUCHED2, G_OLD); /* ... to G_OLD */ 1142 else { /* everything else is removed */
1065 gray2black(curr); /* make it black */ 1143 lua_assert(isold(curr)); /* young objects should be white here */
1066 } 1144 if (getage(curr) == G_TOUCHED2) { /* advance from TOUCHED2... */
1067 /* else, object is white: just remove it from this list */ 1145 changeage(curr, G_TOUCHED2, G_OLD); /* ... to OLD */
1068 *p = *next; /* remove 'curr' from gray list */ 1146 lua_assert(isblack(curr)); /* TOUCHED2 objects are always black */
1069 }
1070 break;
1071 } 1147 }
1072 case LUA_VTHREAD: { 1148 else {
1073 lua_State *th = gco2th(curr); 1149 /* everything else in a gray list should be gray */
1074 lua_assert(!isblack(th)); 1150 lua_assert(isgray(curr));
1075 if (iswhite(th)) /* new object? */ 1151 gray2black(curr); /* make object black (to be removed) */
1076 *p = th->gclist; /* remove from gray list */
1077 else /* old threads remain gray */
1078 p = &th->gclist; /* go to next element */
1079 break;
1080 } 1152 }
1081 default: lua_assert(0); /* nothing more could be gray here */ 1153 goto remove;
1082 } 1154 }
1155 remove: *p = *next; continue;
1156 remain: p = next; continue;
1083 } 1157 }
1084 return p; 1158 return p;
1085} 1159}
@@ -1100,7 +1174,7 @@ static void correctgraylists (global_State *g) {
1100 1174
1101 1175
1102/* 1176/*
1103** Mark 'OLD1' objects when starting a new young collection. 1177** Mark black 'OLD1' objects when starting a new young collection.
1104** Gray objects are already in some gray list, and so will be visited 1178** Gray objects are already in some gray list, and so will be visited
1105** in the atomic step. 1179** in the atomic step.
1106*/ 1180*/
@@ -1109,6 +1183,7 @@ static void markold (global_State *g, GCObject *from, GCObject *to) {
1109 for (p = from; p != to; p = p->next) { 1183 for (p = from; p != to; p = p->next) {
1110 if (getage(p) == G_OLD1) { 1184 if (getage(p) == G_OLD1) {
1111 lua_assert(!iswhite(p)); 1185 lua_assert(!iswhite(p));
1186 changeage(p, G_OLD1, G_OLD); /* now they are old */
1112 if (isblack(p)) { 1187 if (isblack(p)) {
1113 black2gray(p); /* should be '2white', but gray works too */ 1188 black2gray(p); /* should be '2white', but gray works too */
1114 reallymarkobject(g, p); 1189 reallymarkobject(g, p);
@@ -1137,42 +1212,57 @@ static void finishgencycle (lua_State *L, global_State *g) {
1137*/ 1212*/
1138static void youngcollection (lua_State *L, global_State *g) { 1213static void youngcollection (lua_State *L, global_State *g) {
1139 GCObject **psurvival; /* to point to first non-dead survival object */ 1214 GCObject **psurvival; /* to point to first non-dead survival object */
1215 GCObject *dummy; /* dummy out parameter to 'sweepgen' */
1140 lua_assert(g->gcstate == GCSpropagate); 1216 lua_assert(g->gcstate == GCSpropagate);
1141 markold(g, g->allgc, g->reallyold); 1217 if (g->firstold1) { /* are there regular OLD1 objects? */
1218 markold(g, g->firstold1, g->reallyold); /* mark them */
1219 g->firstold1 = NULL; /* no more OLD1 objects (for now) */
1220 }
1142 markold(g, g->finobj, g->finobjrold); 1221 markold(g, g->finobj, g->finobjrold);
1222 markold(g, g->tobefnz, NULL);
1143 atomic(L); 1223 atomic(L);
1144 1224
1145 /* sweep nursery and get a pointer to its last live element */ 1225 /* sweep nursery and get a pointer to its last live element */
1146 psurvival = sweepgen(L, g, &g->allgc, g->survival); 1226 g->gcstate = GCSswpallgc;
1147 /* sweep 'survival' and 'old' */ 1227 psurvival = sweepgen(L, g, &g->allgc, g->survival, &g->firstold1);
1148 sweepgen(L, g, psurvival, g->reallyold); 1228 /* sweep 'survival' */
1149 g->reallyold = g->old; 1229 sweepgen(L, g, psurvival, g->old1, &g->firstold1);
1150 g->old = *psurvival; /* 'survival' survivals are old now */ 1230 g->reallyold = g->old1;
1231 g->old1 = *psurvival; /* 'survival' survivals are old now */
1151 g->survival = g->allgc; /* all news are survivals */ 1232 g->survival = g->allgc; /* all news are survivals */
1152 1233
1153 /* repeat for 'finobj' lists */ 1234 /* repeat for 'finobj' lists */
1154 psurvival = sweepgen(L, g, &g->finobj, g->finobjsur); 1235 dummy = NULL; /* no 'firstold1' optimization for 'finobj' lists */
1155 /* sweep 'survival' and 'old' */ 1236 psurvival = sweepgen(L, g, &g->finobj, g->finobjsur, &dummy);
1156 sweepgen(L, g, psurvival, g->finobjrold); 1237 /* sweep 'survival' */
1157 g->finobjrold = g->finobjold; 1238 sweepgen(L, g, psurvival, g->finobjold1, &dummy);
1158 g->finobjold = *psurvival; /* 'survival' survivals are old now */ 1239 g->finobjrold = g->finobjold1;
1240 g->finobjold1 = *psurvival; /* 'survival' survivals are old now */
1159 g->finobjsur = g->finobj; /* all news are survivals */ 1241 g->finobjsur = g->finobj; /* all news are survivals */
1160 1242
1161 sweepgen(L, g, &g->tobefnz, NULL); 1243 sweepgen(L, g, &g->tobefnz, NULL, &dummy);
1162
1163 finishgencycle(L, g); 1244 finishgencycle(L, g);
1164} 1245}
1165 1246
1166 1247
1248/*
1249** Clears all gray lists, sweeps objects, and prepare sublists to enter
1250** generational mode. The sweeps remove dead objects and turn all
1251** surviving objects to old. Threads go back to 'grayagain'; everything
1252** else is turned black (not in any gray list).
1253*/
1167static void atomic2gen (lua_State *L, global_State *g) { 1254static void atomic2gen (lua_State *L, global_State *g) {
1255 cleargraylists(g);
1168 /* sweep all elements making them old */ 1256 /* sweep all elements making them old */
1257 g->gcstate = GCSswpallgc;
1169 sweep2old(L, &g->allgc); 1258 sweep2old(L, &g->allgc);
1170 /* everything alive now is old */ 1259 /* everything alive now is old */
1171 g->reallyold = g->old = g->survival = g->allgc; 1260 g->reallyold = g->old1 = g->survival = g->allgc;
1261 g->firstold1 = NULL; /* there are no OLD1 objects anywhere */
1172 1262
1173 /* repeat for 'finobj' lists */ 1263 /* repeat for 'finobj' lists */
1174 sweep2old(L, &g->finobj); 1264 sweep2old(L, &g->finobj);
1175 g->finobjrold = g->finobjold = g->finobjsur = g->finobj; 1265 g->finobjrold = g->finobjold1 = g->finobjsur = g->finobj;
1176 1266
1177 sweep2old(L, &g->tobefnz); 1267 sweep2old(L, &g->tobefnz);
1178 1268
@@ -1185,8 +1275,9 @@ static void atomic2gen (lua_State *L, global_State *g) {
1185 1275
1186/* 1276/*
1187** Enter generational mode. Must go until the end of an atomic cycle 1277** Enter generational mode. Must go until the end of an atomic cycle
1188** to ensure that all threads and weak tables are in the gray lists. 1278** to ensure that all objects are correctly marked and weak tables
1189** Then, turn all objects into old and finishes the collection. 1279** are cleared. Then, turn all objects into old and finishes the
1280** collection.
1190*/ 1281*/
1191static lu_mem entergen (lua_State *L, global_State *g) { 1282static lu_mem entergen (lua_State *L, global_State *g) {
1192 lu_mem numobjs; 1283 lu_mem numobjs;
@@ -1205,10 +1296,10 @@ static lu_mem entergen (lua_State *L, global_State *g) {
1205*/ 1296*/
1206static void enterinc (global_State *g) { 1297static void enterinc (global_State *g) {
1207 whitelist(g, g->allgc); 1298 whitelist(g, g->allgc);
1208 g->reallyold = g->old = g->survival = NULL; 1299 g->reallyold = g->old1 = g->survival = NULL;
1209 whitelist(g, g->finobj); 1300 whitelist(g, g->finobj);
1210 whitelist(g, g->tobefnz); 1301 whitelist(g, g->tobefnz);
1211 g->finobjrold = g->finobjold = g->finobjsur = NULL; 1302 g->finobjrold = g->finobjold1 = g->finobjsur = NULL;
1212 g->gcstate = GCSpause; 1303 g->gcstate = GCSpause;
1213 g->gckind = KGC_INC; 1304 g->gckind = KGC_INC;
1214 g->lastatomic = 0; 1305 g->lastatomic = 0;