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

Generated by: LCOV version 2.0-1