75
75
#define set2gray (x ) resetbits(x->marked, maskcolors)
76
76
77
77
78
+ /* make an object black (coming from any color) */
79
+ #define set2black (x ) \
80
+ (x->marked = cast_byte((x->marked & ~WHITEBITS) | bitmask(BLACKBIT)))
81
+
82
+
78
83
#define valiswhite (x ) (iscollectable(x) && iswhite(gcvalue(x)))
79
84
80
85
#define keyiswhite (n ) (keyiscollectable(n) && iswhite(gckey(n)))
@@ -135,15 +140,23 @@ static GCObject **getgclist (GCObject *o) {
135
140
136
141
137
142
/*
138
- ** Link a collectable object 'o' with a known type into list pointed by 'p'.
143
+ ** Link a collectable object 'o' with a known type into the list 'p'.
144
+ ** (Must be a macro to access the 'gclist' field in different types.)
139
145
*/
140
- #define linkgclist (o ,p ) ((o)->gclist = (p), (p) = obj2gco(o))
146
+ #define linkgclist (o ,p ) linkgclist_(obj2gco(o), &(o)->gclist, &(p))
147
+
148
+ static void linkgclist_ (GCObject * o , GCObject * * pnext , GCObject * * list ) {
149
+ lua_assert (!isgray (o )); /* cannot be in a gray list */
150
+ * pnext = * list ;
151
+ * list = o ;
152
+ set2gray (o ); /* now it is */
153
+ }
141
154
142
155
143
156
/*
144
- ** Link a generic collectable object 'o' into list pointed by 'p'.
157
+ ** Link a generic collectable object 'o' into the list 'p'.
145
158
*/
146
- #define linkobjgclist (o ,p ) (*getgclist (o) = (p ), (p) = obj2gco(o ))
159
+ #define linkobjgclist (o ,p ) linkgclist_(obj2gco (o), getgclist(o ), &(p ))
147
160
148
161
149
162
@@ -219,9 +232,10 @@ void luaC_barrierback_ (lua_State *L, GCObject *o) {
219
232
global_State * g = G (L );
220
233
lua_assert (isblack (o ) && !isdead (g , o ));
221
234
lua_assert ((g -> gckind == KGC_GEN ) == (isold (o ) && getage (o ) != G_TOUCHED1 ));
222
- if (getage (o ) != G_TOUCHED2 ) /* not already in gray list? */
223
- linkobjgclist (o , g -> grayagain ); /* link it in 'grayagain' */
224
- set2gray (o ); /* make object gray (again) */
235
+ if (getage (o ) == G_TOUCHED2 ) /* already in gray list? */
236
+ set2gray (o ); /* make it gray to become touched1 */
237
+ else /* link it in 'grayagain' and paint it gray */
238
+ linkobjgclist (o , g -> grayagain );
225
239
if (isold (o )) /* generational mode? */
226
240
setage (o , G_TOUCHED1 ); /* touched in current cycle */
227
241
}
@@ -264,33 +278,38 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
264
278
265
279
266
280
/*
267
- ** Mark an object. Userdata, strings, and closed upvalues are visited
268
- ** and turned black here. Other objects are marked gray and added
269
- ** to appropriate list to be visited (and turned black) later. (Open
270
- ** upvalues are already indirectly linked through the 'twups' list. They
271
- ** are kept gray to avoid barriers, as their values will be revisited by
272
- ** the thread or by 'remarkupvals'.)
281
+ ** Mark an object. Userdata with no user values, strings, and closed
282
+ ** upvalues are visited and turned black here. Open upvalues are
283
+ ** already indirectly linked through their respective threads in the
284
+ ** 'twups' list, so they don't go to the gray list; nevertheless, they
285
+ ** are kept gray to avoid barriers, as their values will be revisited
286
+ ** by the thread or by 'remarkupvals'. Other objects are added to the
287
+ ** gray list to be visited (and turned black) later. Both userdata and
288
+ ** upvalues can call this function recursively, but this recursion goes
289
+ ** for at most two levels: An upvalue cannot refer to another upvalue
290
+ ** (only closures can), and a userdata's metatable must be a table.
273
291
*/
274
292
static void reallymarkobject (global_State * g , GCObject * o ) {
275
- set2gray (o );
276
293
switch (o -> tt ) {
277
294
case LUA_VSHRSTR :
278
295
case LUA_VLNGSTR : {
279
- nw2black (o ); /* nothing to visit */
296
+ set2black (o ); /* nothing to visit */
280
297
break ;
281
298
}
282
299
case LUA_VUPVAL : {
283
300
UpVal * uv = gco2upv (o );
284
- if (!upisopen (uv )) /* open upvalues are kept gray */
285
- nw2black (o ); /* closed upvalues are visited here */
301
+ if (upisopen (uv ))
302
+ set2gray (uv ); /* open upvalues are kept gray */
303
+ else
304
+ set2black (o ); /* closed upvalues are visited here */
286
305
markvalue (g , uv -> v ); /* mark its content */
287
306
break ;
288
307
}
289
308
case LUA_VUSERDATA : {
290
309
Udata * u = gco2u (o );
291
310
if (u -> nuvalue == 0 ) { /* no user values? */
292
311
markobjectN (g , u -> metatable ); /* mark its metatable */
293
- nw2black (o ); /* nothing else to mark */
312
+ set2black (o ); /* nothing else to mark */
294
313
break ;
295
314
}
296
315
/* else... */
@@ -402,17 +421,11 @@ static void restartcollection (global_State *g) {
402
421
** TOUCHED1 objects need to be in the list. TOUCHED2 doesn't need to go
403
422
** back to a gray list, but then it must become OLD. (That is what
404
423
** 'correctgraylist' does when it finds a TOUCHED2 object.)
405
- ** It is defined as a macro because 'gclist' is not a unique field in
406
- ** different collectable objects.
407
424
*/
408
- #define genlink (g ,o ) genlink_(g, obj2gco(o), &(o)->gclist)
409
-
410
- static void genlink_ (global_State * g , GCObject * o , GCObject * * pnext ) {
425
+ static void genlink (global_State * g , GCObject * o ) {
411
426
lua_assert (isblack (o ));
412
427
if (getage (o ) == G_TOUCHED1 ) { /* touched in this cycle? */
413
- * pnext = g -> grayagain ; /* link it back in 'grayagain' */
414
- g -> grayagain = o ;
415
- set2gray (o );
428
+ linkobjgclist (o , g -> grayagain ); /* link it back in 'grayagain' */
416
429
} /* everything else do not need to be linked back */
417
430
else if (getage (o ) == G_TOUCHED2 )
418
431
changeage (o , G_TOUCHED2 , G_OLD ); /* advance age */
@@ -496,10 +509,8 @@ static int traverseephemeron (global_State *g, Table *h, int inv) {
496
509
linkgclist (h , g -> ephemeron ); /* have to propagate again */
497
510
else if (hasclears ) /* table has white keys? */
498
511
linkgclist (h , g -> allweak ); /* may have to clean white keys */
499
- else {
500
- nw2black (h ); /* 'genlink' expects black objects */
501
- genlink (g , h ); /* check whether collector still needs to see it */
502
- }
512
+ else
513
+ genlink (g , obj2gco (h )); /* check whether collector still needs to see it */
503
514
return marked ;
504
515
}
505
516
@@ -519,7 +530,7 @@ static void traversestrongtable (global_State *g, Table *h) {
519
530
markvalue (g , gval (n ));
520
531
}
521
532
}
522
- genlink (g , h );
533
+ genlink (g , obj2gco ( h ) );
523
534
}
524
535
525
536
@@ -531,7 +542,6 @@ static lu_mem traversetable (global_State *g, Table *h) {
531
542
(cast_void (weakkey = strchr (svalue (mode ), 'k' )),
532
543
cast_void (weakvalue = strchr (svalue (mode ), 'v' )),
533
544
(weakkey || weakvalue ))) { /* is really weak? */
534
- set2gray (h ); /* turn it back to gray, as it probably goes to a list */
535
545
if (!weakkey ) /* strong keys? */
536
546
traverseweakvalue (g , h );
537
547
else if (!weakvalue ) /* strong values? */
@@ -550,7 +560,7 @@ static int traverseudata (global_State *g, Udata *u) {
550
560
markobjectN (g , u -> metatable ); /* mark its metatable */
551
561
for (i = 0 ; i < u -> nuvalue ; i ++ )
552
562
markvalue (g , & u -> uv [i ].uv );
553
- genlink (g , u );
563
+ genlink (g , obj2gco ( u ) );
554
564
return 1 + u -> nuvalue ;
555
565
}
556
566
@@ -612,10 +622,8 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
612
622
static int traversethread (global_State * g , lua_State * th ) {
613
623
UpVal * uv ;
614
624
StkId o = th -> stack ;
615
- if (isold (th ) || g -> gcstate == GCSpropagate ) {
625
+ if (isold (th ) || g -> gcstate == GCSpropagate )
616
626
linkgclist (th , g -> grayagain ); /* insert into 'grayagain' list */
617
- set2gray (th );
618
- }
619
627
if (o == NULL )
620
628
return 1 ; /* stack not completely built yet */
621
629
lua_assert (g -> gcstate == GCSatomic ||
@@ -641,8 +649,7 @@ static int traversethread (global_State *g, lua_State *th) {
641
649
642
650
643
651
/*
644
- ** traverse one gray object, turning it to black (except for threads,
645
- ** which are always gray).
652
+ ** traverse one gray object, turning it to black.
646
653
*/
647
654
static lu_mem propagatemark (global_State * g ) {
648
655
GCObject * o = g -> gray ;
@@ -684,8 +691,10 @@ static void convergeephemerons (global_State *g) {
684
691
g -> ephemeron = NULL ; /* tables may return to this list when traversed */
685
692
changed = 0 ;
686
693
while ((w = next ) != NULL ) { /* for each ephemeron table */
687
- next = gco2t (w )-> gclist ; /* list is rebuilt during loop */
688
- if (traverseephemeron (g , gco2t (w ), dir )) { /* marked some value? */
694
+ Table * h = gco2t (w );
695
+ next = h -> gclist ; /* list is rebuilt during loop */
696
+ nw2black (h ); /* out of the list (for now) */
697
+ if (traverseephemeron (g , h , dir )) { /* marked some value? */
689
698
propagateall (g ); /* propagate changes */
690
699
changed = 1 ; /* will have to revisit all ephemeron tables */
691
700
}
@@ -1048,7 +1057,6 @@ static void sweep2old (lua_State *L, GCObject **p) {
1048
1057
if (curr -> tt == LUA_VTHREAD ) { /* threads must be watched */
1049
1058
lua_State * th = gco2th (curr );
1050
1059
linkgclist (th , g -> grayagain ); /* insert into 'grayagain' list */
1051
- set2gray (th );
1052
1060
}
1053
1061
else if (curr -> tt == LUA_VUPVAL && upisopen (gco2upv (curr )))
1054
1062
set2gray (curr ); /* open upvalues are always gray */
@@ -1183,10 +1191,8 @@ static void markold (global_State *g, GCObject *from, GCObject *to) {
1183
1191
if (getage (p ) == G_OLD1 ) {
1184
1192
lua_assert (!iswhite (p ));
1185
1193
changeage (p , G_OLD1 , G_OLD ); /* now they are old */
1186
- if (isblack (p )) {
1187
- set2gray (p ); /* should be '2white', but gray works too */
1194
+ if (isblack (p ))
1188
1195
reallymarkobject (g , p );
1189
- }
1190
1196
}
1191
1197
}
1192
1198
}
0 commit comments