lgc.c
上传用户:jxpjxmjjw
上传日期:2009-12-07
资源大小:5877k
文件大小:13k
源码类别:

模拟服务器

开发平台:

Visual C++

  1. /*
  2. ** $Id: lgc.c,v 1.1 2004/08/20 02:26:56 JH Exp $
  3. ** Garbage Collector
  4. ** See Copyright Notice in lua.h
  5. */
  6. #include <string.h>
  7. #define lgc_c
  8. #include "lua.h"
  9. #include "ldebug.h"
  10. #include "ldo.h"
  11. #include "lfunc.h"
  12. #include "lgc.h"
  13. #include "lmem.h"
  14. #include "lobject.h"
  15. #include "lstate.h"
  16. #include "lstring.h"
  17. #include "ltable.h"
  18. #include "ltm.h"
  19. typedef struct GCState {
  20.   GCObject *tmark;  /* list of marked objects to be traversed */
  21.   GCObject *wk;  /* list of traversed key-weak tables (to be cleared) */
  22.   GCObject *wv;  /* list of traversed value-weak tables */
  23.   GCObject *wkv;  /* list of traversed key-value weak tables */
  24.   global_State *g;
  25. } GCState;
  26. /*
  27. ** some userful bit tricks
  28. */
  29. #define setbit(x,b) ((x) |= (1<<(b)))
  30. #define resetbit(x,b) ((x) &= cast(lu_byte, ~(1<<(b))))
  31. #define testbit(x,b) ((x) & (1<<(b)))
  32. #define unmark(x) resetbit((x)->gch.marked, 0)
  33. #define ismarked(x) ((x)->gch.marked & ((1<<4)|1))
  34. #define stringmark(s) setbit((s)->tsv.marked, 0)
  35. #define isfinalized(u) (!testbit((u)->uv.marked, 1))
  36. #define markfinalized(u) resetbit((u)->uv.marked, 1)
  37. #define KEYWEAKBIT    1
  38. #define VALUEWEAKBIT  2
  39. #define KEYWEAK         (1<<KEYWEAKBIT)
  40. #define VALUEWEAK       (1<<VALUEWEAKBIT)
  41. #define markobject(st,o) { checkconsistency(o); 
  42.   if (iscollectable(o) && !ismarked(gcvalue(o))) reallymarkobject(st,gcvalue(o)); }
  43. #define condmarkobject(st,o,c) { checkconsistency(o); 
  44.   if (iscollectable(o) && !ismarked(gcvalue(o)) && (c)) 
  45.     reallymarkobject(st,gcvalue(o)); }
  46. #define markvalue(st,t) { if (!ismarked(valtogco(t))) 
  47. reallymarkobject(st, valtogco(t)); }
  48. static void reallymarkobject (GCState *st, GCObject *o) {
  49.   lua_assert(!ismarked(o));
  50.   setbit(o->gch.marked, 0);  /* mark object */
  51.   switch (o->gch.tt) {
  52.     case LUA_TUSERDATA: {
  53.       markvalue(st, gcotou(o)->uv.metatable);
  54.       break;
  55.     }
  56.     case LUA_TFUNCTION: {
  57.       gcotocl(o)->c.gclist = st->tmark;
  58.       st->tmark = o;
  59.       break;
  60.     }
  61.     case LUA_TTABLE: {
  62.       gcotoh(o)->gclist = st->tmark;
  63.       st->tmark = o;
  64.       break;
  65.     }
  66.     case LUA_TTHREAD: {
  67.       gcototh(o)->gclist = st->tmark;
  68.       st->tmark = o;
  69.       break;
  70.     }
  71.     case LUA_TPROTO: {
  72.       gcotop(o)->gclist = st->tmark;
  73.       st->tmark = o;
  74.       break;
  75.     }
  76.     default: lua_assert(o->gch.tt == LUA_TSTRING);
  77.   }
  78. }
  79. static void marktmu (GCState *st) {
  80.   GCObject *u;
  81.   for (u = st->g->tmudata; u; u = u->gch.next) {
  82.     unmark(u);  /* may be marked, if left from previous GC */
  83.     reallymarkobject(st, u);
  84.   }
  85. }
  86. /* move `dead' udata that need finalization to list `tmudata' */
  87. size_t luaC_separateudata (lua_State *L) {
  88.   size_t deadmem = 0;
  89.   GCObject **p = &G(L)->rootudata;
  90.   GCObject *curr;
  91.   GCObject *collected = NULL;  /* to collect udata with gc event */
  92.   GCObject **lastcollected = &collected;
  93.   while ((curr = *p) != NULL) {
  94.     lua_assert(curr->gch.tt == LUA_TUSERDATA);
  95.     if (ismarked(curr) || isfinalized(gcotou(curr)))
  96.       p = &curr->gch.next;  /* don't bother with them */
  97.     else if (fasttm(L, gcotou(curr)->uv.metatable, TM_GC) == NULL) {
  98.       markfinalized(gcotou(curr));  /* don't need finalization */
  99.       p = &curr->gch.next;
  100.     }
  101.     else {  /* must call its gc method */
  102.       deadmem += sizeudata(gcotou(curr)->uv.len);
  103.       *p = curr->gch.next;
  104.       curr->gch.next = NULL;  /* link `curr' at the end of `collected' list */
  105.       *lastcollected = curr;
  106.       lastcollected = &curr->gch.next;
  107.     }
  108.   }
  109.   /* insert collected udata with gc event into `tmudata' list */
  110.   *lastcollected = G(L)->tmudata;
  111.   G(L)->tmudata = collected;
  112.   return deadmem;
  113. }
  114. static void removekey (Node *n) {
  115.   setnilvalue(gval(n));  /* remove corresponding value ... */
  116.   if (iscollectable(gkey(n)))
  117.     setttype(gkey(n), LUA_TNONE);  /* dead key; remove it */
  118. }
  119. static void traversetable (GCState *st, Table *h) {
  120.   int i;
  121.   int weakkey = 0;
  122.   int weakvalue = 0;
  123.   const TObject *mode;
  124.   markvalue(st, h->metatable);
  125.   lua_assert(h->lsizenode || h->node == st->g->dummynode);
  126.   mode = gfasttm(st->g, h->metatable, TM_MODE);
  127.   if (mode && ttisstring(mode)) {  /* is there a weak mode? */
  128.     weakkey = (strchr(svalue(mode), 'k') != NULL);
  129.     weakvalue = (strchr(svalue(mode), 'v') != NULL);
  130.     if (weakkey || weakvalue) {  /* is really weak? */
  131.       GCObject **weaklist;
  132.       h->marked &= ~(KEYWEAK | VALUEWEAK);  /* clear bits */
  133.       h->marked |= cast(lu_byte, (weakkey << KEYWEAKBIT) |
  134.                                  (weakvalue << VALUEWEAKBIT));
  135.       weaklist = (weakkey && weakvalue) ? &st->wkv :
  136.                               (weakkey) ? &st->wk :
  137.                                           &st->wv;
  138.       h->gclist = *weaklist;  /* must be cleared after GC, ... */
  139.       *weaklist = valtogco(h);  /* ... so put in the appropriate list */
  140.     }
  141.   }
  142.   if (!weakvalue) {
  143.     i = h->sizearray;
  144.     while (i--)
  145.       markobject(st, &h->array[i]);
  146.   }
  147.   i = sizenode(h);
  148.   while (i--) {
  149.     Node *n = gnode(h, i);
  150.     if (!ttisnil(gval(n))) {
  151.       lua_assert(!ttisnil(gkey(n)));
  152.       condmarkobject(st, gkey(n), !weakkey);
  153.       condmarkobject(st, gval(n), !weakvalue);
  154.     }
  155.   }
  156. }
  157. static void traverseproto (GCState *st, Proto *f) {
  158.   int i;
  159.   stringmark(f->source);
  160.   for (i=0; i<f->sizek; i++) {  /* mark literal strings */
  161.     if (ttisstring(f->k+i))
  162.       stringmark(tsvalue(f->k+i));
  163.   }
  164.   for (i=0; i<f->sizeupvalues; i++)  /* mark upvalue names */
  165.     stringmark(f->upvalues[i]);
  166.   for (i=0; i<f->sizep; i++)  /* mark nested protos */
  167.     markvalue(st, f->p[i]);
  168.   for (i=0; i<f->sizelocvars; i++)  /* mark local-variable names */
  169.     stringmark(f->locvars[i].varname);
  170.   lua_assert(luaG_checkcode(f));
  171. }
  172. static void traverseclosure (GCState *st, Closure *cl) {
  173.   if (cl->c.isC) {
  174.     int i;
  175.     for (i=0; i<cl->c.nupvalues; i++)  /* mark its upvalues */
  176.       markobject(st, &cl->c.upvalue[i]);
  177.   }
  178.   else {
  179.     int i;
  180.     lua_assert(cl->l.nupvalues == cl->l.p->nups);
  181.     markvalue(st, hvalue(&cl->l.g));
  182.     markvalue(st, cl->l.p);
  183.     for (i=0; i<cl->l.nupvalues; i++) {  /* mark its upvalues */
  184.       UpVal *u = cl->l.upvals[i];
  185.       if (!u->marked) {
  186.         markobject(st, &u->value);
  187.         u->marked = 1;
  188.       }
  189.     }
  190.   }
  191. }
  192. static void checkstacksizes (lua_State *L, StkId max) {
  193.   int used = L->ci - L->base_ci;  /* number of `ci' in use */
  194.   if (4*used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci)
  195.     luaD_reallocCI(L, L->size_ci/2);  /* still big enough... */
  196.   else condhardstacktests(luaD_reallocCI(L, L->size_ci));
  197.   used = max - L->stack;  /* part of stack in use */
  198.   if (4*used < L->stacksize && 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize)
  199.     luaD_reallocstack(L, L->stacksize/2);  /* still big enough... */
  200.   else condhardstacktests(luaD_reallocstack(L, L->stacksize));
  201. }
  202. static void traversestack (GCState *st, lua_State *L1) {
  203.   StkId o, lim;
  204.   CallInfo *ci;
  205.   markobject(st, gt(L1));
  206.   lim = L1->top;
  207.   for (ci = L1->base_ci; ci <= L1->ci; ci++) {
  208.     lua_assert(ci->top <= L1->stack_last);
  209.     lua_assert(ci->state & (CI_C | CI_HASFRAME | CI_SAVEDPC));
  210.     if (lim < ci->top)
  211.       lim = ci->top;
  212.   }
  213.   for (o = L1->stack; o < L1->top; o++)
  214.     markobject(st, o);
  215.   for (; o <= lim; o++)
  216.     setnilvalue(o);
  217.   checkstacksizes(L1, lim);
  218. }
  219. static void propagatemarks (GCState *st) {
  220.   while (st->tmark) {  /* traverse marked objects */
  221.     switch (st->tmark->gch.tt) {
  222.       case LUA_TTABLE: {
  223.         Table *h = gcotoh(st->tmark);
  224.         st->tmark = h->gclist;
  225.         traversetable(st, h);
  226.         break;
  227.       }
  228.       case LUA_TFUNCTION: {
  229.         Closure *cl = gcotocl(st->tmark);
  230.         st->tmark = cl->c.gclist;
  231.         traverseclosure(st, cl);
  232.         break;
  233.       }
  234.       case LUA_TTHREAD: {
  235.         lua_State *th = gcototh(st->tmark);
  236.         st->tmark = th->gclist;
  237.         traversestack(st, th);
  238.         break;
  239.       }
  240.       case LUA_TPROTO: {
  241.         Proto *p = gcotop(st->tmark);
  242.         st->tmark = p->gclist;
  243.         traverseproto(st, p);
  244.         break;
  245.       }
  246.       default: lua_assert(0);
  247.     }
  248.   }
  249. }
  250. static int valismarked (const TObject *o) {
  251.   if (ttisstring(o))
  252.     stringmark(tsvalue(o));  /* strings are `values', so are never weak */
  253.   return !iscollectable(o) || testbit(o->value.gc->gch.marked, 0);
  254. }
  255. /*
  256. ** clear collected keys from weaktables
  257. */
  258. static void cleartablekeys (GCObject *l) {
  259.   while (l) {
  260.     Table *h = gcotoh(l);
  261.     int i = sizenode(h);
  262.     lua_assert(h->marked & KEYWEAK);
  263.     while (i--) {
  264.       Node *n = gnode(h, i);
  265.       if (!valismarked(gkey(n)))  /* key was collected? */
  266.         removekey(n);  /* remove entry from table */
  267.     }
  268.     l = h->gclist;
  269.   }
  270. }
  271. /*
  272. ** clear collected values from weaktables
  273. */
  274. static void cleartablevalues (GCObject *l) {
  275.   while (l) {
  276.     Table *h = gcotoh(l);
  277.     int i = h->sizearray;
  278.     lua_assert(h->marked & VALUEWEAK);
  279.     while (i--) {
  280.       TObject *o = &h->array[i];
  281.       if (!valismarked(o))  /* value was collected? */
  282.         setnilvalue(o);  /* remove value */
  283.     }
  284.     i = sizenode(h);
  285.     while (i--) {
  286.       Node *n = gnode(h, i);
  287.       if (!valismarked(gval(n)))  /* value was collected? */
  288.         removekey(n);  /* remove entry from table */
  289.     }
  290.     l = h->gclist;
  291.   }
  292. }
  293. static void freeobj (lua_State *L, GCObject *o) {
  294.   switch (o->gch.tt) {
  295.     case LUA_TPROTO: luaF_freeproto(L, gcotop(o)); break;
  296.     case LUA_TFUNCTION: luaF_freeclosure(L, gcotocl(o)); break;
  297.     case LUA_TUPVAL: luaM_freelem(L, gcotouv(o)); break;
  298.     case LUA_TTABLE: luaH_free(L, gcotoh(o)); break;
  299.     case LUA_TTHREAD: {
  300.       lua_assert(gcototh(o) != L && gcototh(o) != G(L)->mainthread);
  301.       luaE_freethread(L, gcototh(o));
  302.       break;
  303.     }
  304.     case LUA_TSTRING: {
  305.       luaM_free(L, o, sizestring(gcotots(o)->tsv.len));
  306.       break;
  307.     }
  308.     case LUA_TUSERDATA: {
  309.       luaM_free(L, o, sizeudata(gcotou(o)->uv.len));
  310.       break;
  311.     }
  312.     default: lua_assert(0);
  313.   }
  314. }
  315. static int sweeplist (lua_State *L, GCObject **p, int limit) {
  316.   GCObject *curr;
  317.   int count = 0;  /* number of collected items */
  318.   while ((curr = *p) != NULL) {
  319.     if (curr->gch.marked > limit) {
  320.       unmark(curr);
  321.       p = &curr->gch.next;
  322.     }
  323.     else {
  324.       count++;
  325.       *p = curr->gch.next;
  326.       freeobj(L, curr);
  327.     }
  328.   }
  329.   return count;
  330. }
  331. static void sweepstrings (lua_State *L, int all) {
  332.   int i;
  333.   for (i=0; i<G(L)->strt.size; i++) {  /* for each list */
  334.     G(L)->strt.nuse -= sweeplist(L, &G(L)->strt.hash[i], all);
  335.   }
  336. }
  337. static void checkSizes (lua_State *L, size_t deadmem) {
  338.   /* check size of string hash */
  339.   if (G(L)->strt.nuse < cast(ls_nstr, G(L)->strt.size/4) &&
  340.       G(L)->strt.size > MINSTRTABSIZE*2)
  341.     luaS_resize(L, G(L)->strt.size/2);  /* table is too big */
  342.   /* check size of buffer */
  343.   if (luaZ_sizebuffer(&G(L)->buff) > LUA_MINBUFFER*2) {  /* buffer too big? */
  344.     size_t newsize = luaZ_sizebuffer(&G(L)->buff) / 2;
  345.     luaZ_resizebuffer(L, &G(L)->buff, newsize);
  346.   }
  347.   G(L)->GCthreshold = 2*G(L)->nblocks - deadmem;  /* new threshold */
  348. }
  349. static void do1gcTM (lua_State *L, Udata *udata) {
  350.   const TObject *tm = fasttm(L, udata->uv.metatable, TM_GC);
  351.   if (tm != NULL) {
  352.     setobj2s(L->top, tm);
  353.     setuvalue(L->top+1, udata);
  354.     L->top += 2;
  355.     luaD_call(L, L->top - 2, 0);
  356.   }
  357. }
  358. void luaC_callGCTM (lua_State *L) {
  359.   lu_byte oldah = L->allowhook;
  360.   L->allowhook = 0;  /* stop debug hooks during GC tag methods */
  361.   L->top++;  /* reserve space to keep udata while runs its gc method */
  362.   while (G(L)->tmudata != NULL) {
  363.     GCObject *o = G(L)->tmudata;
  364.     Udata *udata = gcotou(o);
  365.     G(L)->tmudata = udata->uv.next;  /* remove udata from `tmudata' */
  366.     udata->uv.next = G(L)->rootudata;  /* return it to `root' list */
  367.     G(L)->rootudata = o;
  368.     setuvalue(L->top - 1, udata);  /* keep a reference to it */
  369.     unmark(o);
  370.     markfinalized(udata);
  371.     do1gcTM(L, udata);
  372.   }
  373.   L->top--;
  374.   L->allowhook = oldah;  /* restore hooks */
  375. }
  376. void luaC_sweep (lua_State *L, int all) {
  377.   if (all) all = 256;  /* larger than any mark */
  378.   sweeplist(L, &G(L)->rootudata, all);
  379.   sweepstrings(L, all);
  380.   sweeplist(L, &G(L)->rootgc, all);
  381. }
  382. /* mark root set */
  383. static void markroot (GCState *st, lua_State *L) {
  384.   global_State *g = st->g;
  385.   markobject(st, defaultmeta(L));
  386.   markobject(st, registry(L));
  387.   traversestack(st, g->mainthread);
  388.   if (L != g->mainthread)  /* another thread is running? */
  389.     markvalue(st, L);  /* cannot collect it */
  390. }
  391. static size_t mark (lua_State *L) {
  392.   size_t deadmem;
  393.   GCState st;
  394.   GCObject *wkv;
  395.   st.g = G(L);
  396.   st.tmark = NULL;
  397.   st.wkv = st.wk = st.wv = NULL;
  398.   markroot(&st, L);
  399.   propagatemarks(&st);  /* mark all reachable objects */
  400.   cleartablevalues(st.wkv);
  401.   cleartablevalues(st.wv);
  402.   wkv = st.wkv;  /* keys must be cleared after preserving udata */
  403.   st.wkv = NULL;
  404.   st.wv = NULL;
  405.   deadmem = luaC_separateudata(L);  /* separate userdata to be preserved */
  406.   marktmu(&st);  /* mark `preserved' userdata */
  407.   propagatemarks(&st);  /* remark, to propagate `preserveness' */
  408.   cleartablekeys(wkv);
  409.   /* `propagatemarks' may resuscitate some weak tables; clear them too */
  410.   cleartablekeys(st.wk);
  411.   cleartablevalues(st.wv);
  412.   cleartablekeys(st.wkv);
  413.   cleartablevalues(st.wkv);
  414.   return deadmem;
  415. }
  416. void luaC_collectgarbage (lua_State *L) {
  417.   size_t deadmem = mark(L);
  418.   luaC_sweep(L, 0);
  419.   checkSizes(L, deadmem);
  420.   luaC_callGCTM(L);
  421. }
  422. void luaC_link (lua_State *L, GCObject *o, lu_byte tt) {
  423.   o->gch.next = G(L)->rootgc;
  424.   G(L)->rootgc = o;
  425.   o->gch.marked = 0;
  426.   o->gch.tt = tt;
  427. }