LCOV - code coverage report
Current view: directory - src - lgc.c Found Hit Coverage
Test: Lua 5.1.4 Lines: 384 368 95.8 %
Date: 2009-09-13
Colors: not hit hit

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

Generated by: LCOV version 1.7