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