misc/liblua/lgc.c
changeset 2812 0a24853de796
child 3697 d5b30d6373fc
equal deleted inserted replaced
2811:4cad87e11bf6 2812:0a24853de796
       
     1 /*
       
     2 ** $Id: lgc.c,v 2.38.1.1 2007/12/27 13:02:25 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     lua_assert(g->totalbytes >= g->estimate);
       
   631     setthreshold(g);
       
   632   }
       
   633 }
       
   634 
       
   635 
       
   636 void luaC_fullgc (lua_State *L) {
       
   637   global_State *g = G(L);
       
   638   if (g->gcstate <= GCSpropagate) {
       
   639     /* reset sweep marks to sweep all elements (returning them to white) */
       
   640     g->sweepstrgc = 0;
       
   641     g->sweepgc = &g->rootgc;
       
   642     /* reset other collector lists */
       
   643     g->gray = NULL;
       
   644     g->grayagain = NULL;
       
   645     g->weak = NULL;
       
   646     g->gcstate = GCSsweepstring;
       
   647   }
       
   648   lua_assert(g->gcstate != GCSpause && g->gcstate != GCSpropagate);
       
   649   /* finish any pending sweep phase */
       
   650   while (g->gcstate != GCSfinalize) {
       
   651     lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep);
       
   652     singlestep(L);
       
   653   }
       
   654   markroot(L);
       
   655   while (g->gcstate != GCSpause) {
       
   656     singlestep(L);
       
   657   }
       
   658   setthreshold(g);
       
   659 }
       
   660 
       
   661 
       
   662 void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
       
   663   global_State *g = G(L);
       
   664   lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
       
   665   lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
       
   666   lua_assert(ttype(&o->gch) != LUA_TTABLE);
       
   667   /* must keep invariant? */
       
   668   if (g->gcstate == GCSpropagate)
       
   669     reallymarkobject(g, v);  /* restore invariant */
       
   670   else  /* don't mind */
       
   671     makewhite(g, o);  /* mark as white just to avoid other barriers */
       
   672 }
       
   673 
       
   674 
       
   675 void luaC_barrierback (lua_State *L, Table *t) {
       
   676   global_State *g = G(L);
       
   677   GCObject *o = obj2gco(t);
       
   678   lua_assert(isblack(o) && !isdead(g, o));
       
   679   lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
       
   680   black2gray(o);  /* make table gray (again) */
       
   681   t->gclist = g->grayagain;
       
   682   g->grayagain = o;
       
   683 }
       
   684 
       
   685 
       
   686 void luaC_link (lua_State *L, GCObject *o, lu_byte tt) {
       
   687   global_State *g = G(L);
       
   688   o->gch.next = g->rootgc;
       
   689   g->rootgc = o;
       
   690   o->gch.marked = luaC_white(g);
       
   691   o->gch.tt = tt;
       
   692 }
       
   693 
       
   694 
       
   695 void luaC_linkupval (lua_State *L, UpVal *uv) {
       
   696   global_State *g = G(L);
       
   697   GCObject *o = obj2gco(uv);
       
   698   o->gch.next = g->rootgc;  /* link upvalue into `rootgc' list */
       
   699   g->rootgc = o;
       
   700   if (isgray(o)) { 
       
   701     if (g->gcstate == GCSpropagate) {
       
   702       gray2black(o);  /* closed upvalues need barrier */
       
   703       luaC_barrier(L, uv, uv->v);
       
   704     }
       
   705     else {  /* sweep phase: sweep it (turning it into white) */
       
   706       makewhite(g, o);
       
   707       lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
       
   708     }
       
   709   }
       
   710 }
       
   711