1 /*
2 ** $Id$
3 ** Garbage Collector
4 ** See Copyright Notice in lua.h
5 */
6 
7 #define lgc_c
8 #define LUA_CORE
9 
10 #include "lua.h"
11 
12 #include "ldebug.h"
13 #include "ldo.h"
14 #include "lfunc.h"
15 #include "lgc.h"
16 #include "lmem.h"
17 #include "lobject.h"
18 #include "lstate.h"
19 #include "lstring.h"
20 #include "ltable.h"
21 #include "ltm.h"
22 
23 
24 #define GCSTEPSIZE	1024u
25 #define GCSWEEPMAX	40
26 #define GCSWEEPCOST	10
27 #define GCFINALIZECOST	100
28 
29 
30 #define maskmarks	cast_byte(~(bitmask(BLACKBIT)|WHITEBITS))
31 
32 #define makewhite(g,x)	\
33    ((x)->gch.marked = cast_byte(((x)->gch.marked & maskmarks) | luaC_white(g)))
34 
35 #define white2gray(x)	reset2bits((x)->gch.marked, WHITE0BIT, WHITE1BIT)
36 #define black2gray(x)	resetbit((x)->gch.marked, BLACKBIT)
37 
38 #define stringmark(s)	reset2bits((s)->tsv.marked, WHITE0BIT, WHITE1BIT)
39 
40 
41 #define isfinalized(u)		testbit((u)->marked, FINALIZEDBIT)
42 #define markfinalized(u)	l_setbit((u)->marked, FINALIZEDBIT)
43 
44 
45 #define KEYWEAK         bitmask(KEYWEAKBIT)
46 #define VALUEWEAK       bitmask(VALUEWEAKBIT)
47 
48 
49 
50 #define markvalue(g,o) { checkconsistency(o); \
51   if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); }
52 
53 #define markobject(g,t) { if (iswhite(obj2gco(t))) \
54 		reallymarkobject(g, obj2gco(t)); }
55 
56 
57 #define setthreshold(g)  (g->GCthreshold = (g->estimate/100) * g->gcpause)
58 
59 
removeentry(Node * n)60 static void removeentry (Node *n) {
61   lua_assert(ttisnil(gval(n)));
62   if (iscollectable(gkey(n)))
63     setttype(gkey(n), LUA_TDEADKEY);  /* dead key; remove it */
64 }
65 
66 
reallymarkobject(global_State * g,GCObject * o)67 static void reallymarkobject (global_State *g, GCObject *o) {
68   lua_assert(iswhite(o) && !isdead(g, o));
69   white2gray(o);
70   switch (o->gch.tt) {
71     case LUA_TSTRING: {
72       return;
73     }
74     case LUA_TUSERDATA: {
75       Table *mt = gco2u(o)->metatable;
76       gray2black(o);  /* udata are never gray */
77       if (mt) markobject(g, mt);
78       markobject(g, gco2u(o)->env);
79       return;
80     }
81     case LUA_TUPVAL: {
82       UpVal *uv = gco2uv(o);
83       markvalue(g, uv->v);
84       if (uv->v == &uv->u.value)  /* closed? */
85         gray2black(o);  /* open upvalues are never black */
86       return;
87     }
88     case LUA_TFUNCTION: {
89       gco2cl(o)->c.gclist = g->gray;
90       g->gray = o;
91       break;
92     }
93     case LUA_TTABLE: {
94       gco2h(o)->gclist = g->gray;
95       g->gray = o;
96       break;
97     }
98     case LUA_TTHREAD: {
99       gco2th(o)->gclist = g->gray;
100       g->gray = o;
101       break;
102     }
103     case LUA_TPROTO: {
104       gco2p(o)->gclist = g->gray;
105       g->gray = o;
106       break;
107     }
108     default: lua_assert(0);
109   }
110 }
111 
112 
marktmu(global_State * g)113 static void marktmu (global_State *g) {
114   GCObject *u = g->tmudata;
115   if (u) {
116     do {
117       u = u->gch.next;
118       makewhite(g, u);  /* may be marked, if left from previous GC */
119       reallymarkobject(g, u);
120     } while (u != g->tmudata);
121   }
122 }
123 
124 
125 /* move `dead' udata that need finalization to list `tmudata' */
luaC_separateudata(lua_State * L,int all)126 size_t luaC_separateudata (lua_State *L, int all) {
127   global_State *g = G(L);
128   size_t deadmem = 0;
129   GCObject **p = &g->mainthread->next;
130   GCObject *curr;
131   while ((curr = *p) != NULL) {
132     if (!(iswhite(curr) || all) || isfinalized(gco2u(curr)))
133       p = &curr->gch.next;  /* don't bother with them */
134     else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) {
135       markfinalized(gco2u(curr));  /* don't need finalization */
136       p = &curr->gch.next;
137     }
138     else {  /* must call its gc method */
139       deadmem += sizeudata(gco2u(curr));
140       markfinalized(gco2u(curr));
141       *p = curr->gch.next;
142       /* link `curr' at the end of `tmudata' list */
143       if (g->tmudata == NULL)  /* list is empty? */
144         g->tmudata = curr->gch.next = curr;  /* creates a circular list */
145       else {
146         curr->gch.next = g->tmudata->gch.next;
147         g->tmudata->gch.next = curr;
148         g->tmudata = curr;
149       }
150     }
151   }
152   return deadmem;
153 }
154 
155 
traversetable(global_State * g,Table * h)156 static int traversetable (global_State *g, Table *h) {
157   int i;
158   int weakkey = 0;
159   int weakvalue = 0;
160   const TValue *mode;
161   if (h->metatable)
162     markobject(g, h->metatable);
163   mode = gfasttm(g, h->metatable, TM_MODE);
164   if (mode && ttisstring(mode)) {  /* is there a weak mode? */
165     weakkey = (strchr(svalue(mode), 'k') != NULL);
166     weakvalue = (strchr(svalue(mode), 'v') != NULL);
167     if (weakkey || weakvalue) {  /* is really weak? */
168       h->marked &= ~(KEYWEAK | VALUEWEAK);  /* clear bits */
169       h->marked |= cast_byte((weakkey << KEYWEAKBIT) |
170                              (weakvalue << VALUEWEAKBIT));
171       h->gclist = g->weak;  /* must be cleared after GC, ... */
172       g->weak = obj2gco(h);  /* ... so put in the appropriate list */
173     }
174   }
175   if (weakkey && weakvalue) return 1;
176   if (!weakvalue) {
177     i = h->sizearray;
178     while (i--)
179       markvalue(g, &h->array[i]);
180   }
181   i = sizenode(h);
182   while (i--) {
183     Node *n = gnode(h, i);
184     lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n)));
185     if (ttisnil(gval(n)))
186       removeentry(n);  /* remove empty entries */
187     else {
188       lua_assert(!ttisnil(gkey(n)));
189       if (!weakkey) markvalue(g, gkey(n));
190       if (!weakvalue) markvalue(g, gval(n));
191     }
192   }
193   return weakkey || weakvalue;
194 }
195 
196 
197 /*
198 ** All marks are conditional because a GC may happen while the
199 ** prototype is still being created
200 */
traverseproto(global_State * g,Proto * f)201 static void traverseproto (global_State *g, Proto *f) {
202   int i;
203   if (f->source) stringmark(f->source);
204   for (i=0; i<f->sizek; i++)  /* mark literals */
205     markvalue(g, &f->k[i]);
206   for (i=0; i<f->sizeupvalues; i++) {  /* mark upvalue names */
207     if (f->upvalues[i])
208       stringmark(f->upvalues[i]);
209   }
210   for (i=0; i<f->sizep; i++) {  /* mark nested protos */
211     if (f->p[i])
212       markobject(g, f->p[i]);
213   }
214   for (i=0; i<f->sizelocvars; i++) {  /* mark local-variable names */
215     if (f->locvars[i].varname)
216       stringmark(f->locvars[i].varname);
217   }
218 }
219 
220 
221 
traverseclosure(global_State * g,Closure * cl)222 static void traverseclosure (global_State *g, Closure *cl) {
223   markobject(g, cl->c.env);
224   if (cl->c.isC) {
225     int i;
226     for (i=0; i<cl->c.nupvalues; i++)  /* mark its upvalues */
227       markvalue(g, &cl->c.upvalue[i]);
228   }
229   else {
230     int i;
231     lua_assert(cl->l.nupvalues == cl->l.p->nups);
232     markobject(g, cl->l.p);
233     for (i=0; i<cl->l.nupvalues; i++)  /* mark its upvalues */
234       markobject(g, cl->l.upvals[i]);
235   }
236 }
237 
238 
checkstacksizes(lua_State * L,StkId max)239 static void checkstacksizes (lua_State *L, StkId max) {
240   int ci_used = cast_int(L->ci - L->base_ci);  /* number of `ci' in use */
241   int s_used = cast_int(max - L->stack);  /* part of stack in use */
242   if (L->size_ci > LUAI_MAXCALLS)  /* handling overflow? */
243     return;  /* do not touch the stacks */
244   if (4*ci_used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci)
245     luaD_reallocCI(L, L->size_ci/2);  /* still big enough... */
246   condhardstacktests(luaD_reallocCI(L, ci_used + 1));
247   if (4*s_used < L->stacksize &&
248       2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize)
249     luaD_reallocstack(L, L->stacksize/2);  /* still big enough... */
250   condhardstacktests(luaD_reallocstack(L, s_used));
251 }
252 
253 
traversestack(global_State * g,lua_State * l)254 static void traversestack (global_State *g, lua_State *l) {
255   StkId o, lim;
256   CallInfo *ci;
257   markvalue(g, gt(l));
258   lim = l->top;
259   for (ci = l->base_ci; ci <= l->ci; ci++) {
260     lua_assert(ci->top <= l->stack_last);
261     if (lim < ci->top) lim = ci->top;
262   }
263   for (o = l->stack; o < l->top; o++)
264     markvalue(g, o);
265   for (; o <= lim; o++)
266     setnilvalue(o);
267   checkstacksizes(l, lim);
268 }
269 
270 
271 /*
272 ** traverse one gray object, turning it to black.
273 ** Returns `quantity' traversed.
274 */
propagatemark(global_State * g)275 static l_mem propagatemark (global_State *g) {
276   GCObject *o = g->gray;
277   lua_assert(isgray(o));
278   gray2black(o);
279   switch (o->gch.tt) {
280     case LUA_TTABLE: {
281       Table *h = gco2h(o);
282       g->gray = h->gclist;
283       if (traversetable(g, h))  /* table is weak? */
284         black2gray(o);  /* keep it gray */
285       return sizeof(Table) + sizeof(TValue) * h->sizearray +
286                              sizeof(Node) * sizenode(h);
287     }
288     case LUA_TFUNCTION: {
289       Closure *cl = gco2cl(o);
290       g->gray = cl->c.gclist;
291       traverseclosure(g, cl);
292       return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) :
293                            sizeLclosure(cl->l.nupvalues);
294     }
295     case LUA_TTHREAD: {
296       lua_State *th = gco2th(o);
297       g->gray = th->gclist;
298       th->gclist = g->grayagain;
299       g->grayagain = o;
300       black2gray(o);
301       traversestack(g, th);
302       return sizeof(lua_State) + sizeof(TValue) * th->stacksize +
303                                  sizeof(CallInfo) * th->size_ci;
304     }
305     case LUA_TPROTO: {
306       Proto *p = gco2p(o);
307       g->gray = p->gclist;
308       traverseproto(g, p);
309       return sizeof(Proto) + sizeof(Instruction) * p->sizecode +
310                              sizeof(Proto *) * p->sizep +
311                              sizeof(TValue) * p->sizek +
312                              sizeof(int) * p->sizelineinfo +
313                              sizeof(LocVar) * p->sizelocvars +
314                              sizeof(TString *) * p->sizeupvalues;
315     }
316     default: lua_assert(0); return 0;
317   }
318 }
319 
320 
propagateall(global_State * g)321 static size_t propagateall (global_State *g) {
322   size_t m = 0;
323   while (g->gray) m += propagatemark(g);
324   return m;
325 }
326 
327 
328 /*
329 ** The next function tells whether a key or value can be cleared from
330 ** a weak table. Non-collectable objects are never removed from weak
331 ** tables. Strings behave as `values', so are never removed too. for
332 ** other objects: if really collected, cannot keep them; for userdata
333 ** being finalized, keep them in keys, but not in values
334 */
iscleared(const TValue * o,int iskey)335 static int iscleared (const TValue *o, int iskey) {
336   if (!iscollectable(o)) return 0;
337   if (ttisstring(o)) {
338     stringmark(rawtsvalue(o));  /* strings are `values', so are never weak */
339     return 0;
340   }
341   return iswhite(gcvalue(o)) ||
342     (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o))));
343 }
344 
345 
346 /*
347 ** clear collected entries from weaktables
348 */
cleartable(GCObject * l)349 static void cleartable (GCObject *l) {
350   while (l) {
351     Table *h = gco2h(l);
352     int i = h->sizearray;
353     lua_assert(testbit(h->marked, VALUEWEAKBIT) ||
354                testbit(h->marked, KEYWEAKBIT));
355     if (testbit(h->marked, VALUEWEAKBIT)) {
356       while (i--) {
357         TValue *o = &h->array[i];
358         if (iscleared(o, 0))  /* value was collected? */
359           setnilvalue(o);  /* remove value */
360       }
361     }
362     i = sizenode(h);
363     while (i--) {
364       Node *n = gnode(h, i);
365       if (!ttisnil(gval(n)) &&  /* non-empty entry? */
366           (iscleared(key2tval(n), 1) || iscleared(gval(n), 0))) {
367         setnilvalue(gval(n));  /* remove value ... */
368         removeentry(n);  /* remove entry from table */
369       }
370     }
371     l = h->gclist;
372   }
373 }
374 
375 
freeobj(lua_State * L,GCObject * o)376 static void freeobj (lua_State *L, GCObject *o) {
377   switch (o->gch.tt) {
378     case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break;
379     case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break;
380     case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break;
381     case LUA_TTABLE: luaH_free(L, gco2h(o)); break;
382     case LUA_TTHREAD: {
383       lua_assert(gco2th(o) != L && gco2th(o) != G(L)->mainthread);
384       luaE_freethread(L, gco2th(o));
385       break;
386     }
387     case LUA_TSTRING: {
388       G(L)->strt.nuse--;
389       luaM_freemem(L, o, sizestring(gco2ts(o)));
390       break;
391     }
392     case LUA_TUSERDATA: {
393       luaM_freemem(L, o, sizeudata(gco2u(o)));
394       break;
395     }
396     default: lua_assert(0);
397   }
398 }
399 
400 
401 
402 #define sweepwholelist(L,p)	sweeplist(L,p,MAX_LUMEM)
403 
404 
sweeplist(lua_State * L,GCObject ** p,lu_mem count)405 static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
406   GCObject *curr;
407   global_State *g = G(L);
408   int deadmask = otherwhite(g);
409   while ((curr = *p) != NULL && count-- > 0) {
410     if (curr->gch.tt == LUA_TTHREAD)  /* sweep open upvalues of each thread */
411       sweepwholelist(L, &gco2th(curr)->openupval);
412     if ((curr->gch.marked ^ WHITEBITS) & deadmask) {  /* not dead? */
413       lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT));
414       makewhite(g, curr);  /* make it white (for next cycle) */
415       p = &curr->gch.next;
416     }
417     else {  /* must erase `curr' */
418       lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT));
419       *p = curr->gch.next;
420       if (curr == g->rootgc)  /* is the first element of the list? */
421         g->rootgc = curr->gch.next;  /* adjust first */
422       freeobj(L, curr);
423     }
424   }
425   return p;
426 }
427 
428 
checkSizes(lua_State * L)429 static void checkSizes (lua_State *L) {
430   global_State *g = G(L);
431   /* check size of string hash */
432   if (g->strt.nuse < cast(lu_int32, g->strt.size/4) &&
433       g->strt.size > MINSTRTABSIZE*2)
434     luaS_resize(L, g->strt.size/2);  /* table is too big */
435   /* check size of buffer */
436   if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) {  /* buffer too big? */
437     size_t newsize = luaZ_sizebuffer(&g->buff) / 2;
438     luaZ_resizebuffer(L, &g->buff, newsize);
439   }
440 }
441 
442 
GCTM(lua_State * L)443 static void GCTM (lua_State *L) {
444   global_State *g = G(L);
445   GCObject *o = g->tmudata->gch.next;  /* get first element */
446   Udata *udata = rawgco2u(o);
447   const TValue *tm;
448   /* remove udata from `tmudata' */
449   if (o == g->tmudata)  /* last element? */
450     g->tmudata = NULL;
451   else
452     g->tmudata->gch.next = udata->uv.next;
453   udata->uv.next = g->mainthread->next;  /* return it to `root' list */
454   g->mainthread->next = o;
455   makewhite(g, o);
456   tm = fasttm(L, udata->uv.metatable, TM_GC);
457   if (tm != NULL) {
458     lu_byte oldah = L->allowhook;
459     lu_mem oldt = g->GCthreshold;
460     L->allowhook = 0;  /* stop debug hooks during GC tag method */
461     g->GCthreshold = 2*g->totalbytes;  /* avoid GC steps */
462     setobj2s(L, L->top, tm);
463     setuvalue(L, L->top+1, udata);
464     L->top += 2;
465     luaD_call(L, L->top - 2, 0);
466     L->allowhook = oldah;  /* restore hooks */
467     g->GCthreshold = oldt;  /* restore threshold */
468   }
469 }
470 
471 
472 /*
473 ** Call all GC tag methods
474 */
luaC_callGCTM(lua_State * L)475 void luaC_callGCTM (lua_State *L) {
476   while (G(L)->tmudata)
477     GCTM(L);
478 }
479 
480 
luaC_freeall(lua_State * L)481 void luaC_freeall (lua_State *L) {
482   global_State *g = G(L);
483   int i;
484   g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT);  /* mask to collect all elements */
485   sweepwholelist(L, &g->rootgc);
486   for (i = 0; i < g->strt.size; i++)  /* free all string lists */
487     sweepwholelist(L, &g->strt.hash[i]);
488 }
489 
490 
markmt(global_State * g)491 static void markmt (global_State *g) {
492   int i;
493   for (i=0; i<NUM_TAGS; i++)
494     if (g->mt[i]) markobject(g, g->mt[i]);
495 }
496 
497 
498 /* mark root set */
markroot(lua_State * L)499 static void markroot (lua_State *L) {
500   global_State *g = G(L);
501   g->gray = NULL;
502   g->grayagain = NULL;
503   g->weak = NULL;
504   markobject(g, g->mainthread);
505   /* make global table be traversed before main stack */
506   markvalue(g, gt(g->mainthread));
507   markvalue(g, registry(L));
508   markmt(g);
509   g->gcstate = GCSpropagate;
510 }
511 
512 
remarkupvals(global_State * g)513 static void remarkupvals (global_State *g) {
514   UpVal *uv;
515   for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) {
516     lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
517     if (isgray(obj2gco(uv)))
518       markvalue(g, uv->v);
519   }
520 }
521 
522 
atomic(lua_State * L)523 static void atomic (lua_State *L) {
524   global_State *g = G(L);
525   size_t udsize;  /* total size of userdata to be finalized */
526   /* remark occasional upvalues of (maybe) dead threads */
527   remarkupvals(g);
528   /* traverse objects cautch by write barrier and by 'remarkupvals' */
529   propagateall(g);
530   /* remark weak tables */
531   g->gray = g->weak;
532   g->weak = NULL;
533   lua_assert(!iswhite(obj2gco(g->mainthread)));
534   markobject(g, L);  /* mark running thread */
535   markmt(g);  /* mark basic metatables (again) */
536   propagateall(g);
537   /* remark gray again */
538   g->gray = g->grayagain;
539   g->grayagain = NULL;
540   propagateall(g);
541   udsize = luaC_separateudata(L, 0);  /* separate userdata to be finalized */
542   marktmu(g);  /* mark `preserved' userdata */
543   udsize += propagateall(g);  /* remark, to propagate `preserveness' */
544   cleartable(g->weak);  /* remove collected objects from weak tables */
545   /* flip current white */
546   g->currentwhite = cast_byte(otherwhite(g));
547   g->sweepstrgc = 0;
548   g->sweepgc = &g->rootgc;
549   g->gcstate = GCSsweepstring;
550   g->estimate = g->totalbytes - udsize;  /* first estimate */
551 }
552 
553 
singlestep(lua_State * L)554 static l_mem singlestep (lua_State *L) {
555   global_State *g = G(L);
556   /*lua_checkmemory(L);*/
557   switch (g->gcstate) {
558     case GCSpause: {
559       markroot(L);  /* start a new collection */
560       return 0;
561     }
562     case GCSpropagate: {
563       if (g->gray)
564         return propagatemark(g);
565       else {  /* no more `gray' objects */
566         atomic(L);  /* finish mark phase */
567         return 0;
568       }
569     }
570     case GCSsweepstring: {
571       lu_mem old = g->totalbytes;
572       sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
573       if (g->sweepstrgc >= g->strt.size)  /* nothing more to sweep? */
574         g->gcstate = GCSsweep;  /* end sweep-string phase */
575       lua_assert(old >= g->totalbytes);
576       g->estimate -= old - g->totalbytes;
577       return GCSWEEPCOST;
578     }
579     case GCSsweep: {
580       lu_mem old = g->totalbytes;
581       g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
582       if (*g->sweepgc == NULL) {  /* nothing more to sweep? */
583         checkSizes(L);
584         g->gcstate = GCSfinalize;  /* end sweep phase */
585       }
586       lua_assert(old >= g->totalbytes);
587       g->estimate -= old - g->totalbytes;
588       return GCSWEEPMAX*GCSWEEPCOST;
589     }
590     case GCSfinalize: {
591       if (g->tmudata) {
592         GCTM(L);
593         if (g->estimate > GCFINALIZECOST)
594           g->estimate -= GCFINALIZECOST;
595         return GCFINALIZECOST;
596       }
597       else {
598         g->gcstate = GCSpause;  /* end collection */
599         g->gcdept = 0;
600         return 0;
601       }
602     }
603     default: lua_assert(0); return 0;
604   }
605 }
606 
607 
luaC_step(lua_State * L)608 void luaC_step (lua_State *L) {
609   global_State *g = G(L);
610   l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul;
611   if (lim == 0)
612     lim = (MAX_LUMEM-1)/2;  /* no limit */
613   g->gcdept += g->totalbytes - g->GCthreshold;
614   do {
615     lim -= singlestep(L);
616     if (g->gcstate == GCSpause)
617       break;
618   } while (lim > 0);
619   if (g->gcstate != GCSpause) {
620     if (g->gcdept < GCSTEPSIZE)
621       g->GCthreshold = g->totalbytes + GCSTEPSIZE;  /* - lim/g->gcstepmul;*/
622     else {
623       g->gcdept -= GCSTEPSIZE;
624       g->GCthreshold = g->totalbytes;
625     }
626   }
627   else {
628     lua_assert(g->totalbytes >= g->estimate);
629     setthreshold(g);
630   }
631 }
632 
633 
luaC_fullgc(lua_State * L)634 void luaC_fullgc (lua_State *L) {
635   global_State *g = G(L);
636   if (g->gcstate <= GCSpropagate) {
637     /* reset sweep marks to sweep all elements (returning them to white) */
638     g->sweepstrgc = 0;
639     g->sweepgc = &g->rootgc;
640     /* reset other collector lists */
641     g->gray = NULL;
642     g->grayagain = NULL;
643     g->weak = NULL;
644     g->gcstate = GCSsweepstring;
645   }
646   lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate);
647   /* finish any pending sweep phase */
648   while (g->gcstate != GCSfinalize) {
649     lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep);
650     singlestep(L);
651   }
652   markroot(L);
653   while (g->gcstate != GCSpause) {
654     singlestep(L);
655   }
656   setthreshold(g);
657 }
658 
659 
luaC_barrierf(lua_State * L,GCObject * o,GCObject * v)660 void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
661   global_State *g = G(L);
662   lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
663   lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
664   lua_assert(ttype(&o->gch) != LUA_TTABLE);
665   /* must keep invariant? */
666   if (g->gcstate == GCSpropagate)
667     reallymarkobject(g, v);  /* restore invariant */
668   else  /* don't mind */
669     makewhite(g, o);  /* mark as white just to avoid other barriers */
670 }
671 
672 
luaC_barrierback(lua_State * L,Table * t)673 void luaC_barrierback (lua_State *L, Table *t) {
674   global_State *g = G(L);
675   GCObject *o = obj2gco(t);
676   lua_assert(isblack(o) && !isdead(g, o));
677   lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
678   black2gray(o);  /* make table gray (again) */
679   t->gclist = g->grayagain;
680   g->grayagain = o;
681 }
682 
683 
luaC_link(lua_State * L,GCObject * o,lu_byte tt)684 void luaC_link (lua_State *L, GCObject *o, lu_byte tt) {
685   global_State *g = G(L);
686   o->gch.next = g->rootgc;
687   g->rootgc = o;
688   o->gch.marked = luaC_white(g);
689   o->gch.tt = tt;
690 }
691 
692 
luaC_linkupval(lua_State * L,UpVal * uv)693 void luaC_linkupval (lua_State *L, UpVal *uv) {
694   global_State *g = G(L);
695   GCObject *o = obj2gco(uv);
696   o->gch.next = g->rootgc;  /* link upvalue into `rootgc' list */
697   g->rootgc = o;
698   if (isgray(o)) {
699     if (g->gcstate == GCSpropagate) {
700       gray2black(o);  /* closed upvalues need barrier */
701       luaC_barrier(L, uv, uv->v);
702     }
703     else {  /* sweep phase: sweep it (turning it into white) */
704       makewhite(g, o);
705       lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
706     }
707   }
708 }
709