LCOV - code coverage report
Current view: top level - src - lgc.c Hit Total Coverage
Test: Lua 5.1.5 Lines: 379 398 95.2 %
Date: 2017-04-16 16:03:13
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13