Beispiel #1
0
/*
** mark an object. Userdata, strings, and closed upvalues are visited
** and turned black here. Other objects are marked gray and added
** to appropriate list to be visited (and turned black) later. (Open
** upvalues are already linked in 'headuv' list.)
*/
static void reallymarkobject (global_State *g, GCObject *o) {
reentry:
    white2gray(o);
    switch (o->tt) {
    case LUA_TSHRSTR: {
        gray2black(o);
        g->GCmemtrav += sizelstring(gco2ts(o)->shrlen);
        break;
    }
    case LUA_TLNGSTR: {
        gray2black(o);
        g->GCmemtrav += sizelstring(gco2ts(o)->u.lnglen);
        break;
    }
    case LUA_TUSERDATA: {
        TValue uvalue;
        markobjectN(g, gco2u(o)->metatable);  /* mark its metatable */
        gray2black(o);
        g->GCmemtrav += sizeudata(gco2u(o));
        getuservalue(g->mainthread, gco2u(o), &uvalue);
        if (valiswhite(&uvalue)) {  /* markvalue(g, &uvalue); */
            o = gcvalue(&uvalue);
            goto reentry;
        }
        break;
    }
    case LUA_TLCL: {
        linkgclist(gco2lcl(o), g->gray);
        break;
    }
    case LUA_TCCL: {
        linkgclist(gco2ccl(o), g->gray);
        break;
    }
    case LUA_TTABLE: {
        linkgclist(gco2t(o), g->gray);
        break;
    }
    case LUA_TTHREAD: {
        linkgclist(gco2th(o), g->gray);
        break;
    }
    case LUA_TPROTO: {
        linkgclist(gco2p(o), g->gray);
        break;
    }
    default:
        lua_assert(0);
        break;
    }
}
Beispiel #2
0
/*
** Traverse a table with weak values and link it to proper list. During
** propagate phase, keep it in 'grayagain' list, to be revisited in the
** atomic phase. In the atomic phase, if table has any white value,
** put it in 'weak' list, to be cleared.
*/
static void traverseweakvalue (global_State *g, Table *h) {
  Node *n, *limit = gnodelast(h);
  /* if there is array part, assume it may have white values (it is not
     worth traversing it now just to check) */
  int hasclears = (h->sizearray > 0);
  for (n = gnode(h, 0); n < limit; n++) {  /* traverse hash part */
    checkdeadkey(n);
    if (ttisnil(gval(n)))  /* entry is empty? */
      removeentry(n);  /* remove it */
    else {
      lua_assert(!ttisnil(gkey(n)));
      markvalue(g, gkey(n));  /* mark key */
      if (!hasclears && iscleared(g, gval(n)))  /* is there a white value? */
        hasclears = 1;  /* table will have to be cleared */
    }
  }
  if (g->gcstate == GCSpropagate)
    linkgclist(h, g->grayagain);  /* must retraverse it in atomic phase */
  else if (hasclears)
    linkgclist(h, g->weak);  /* has to be cleared later */
}
Beispiel #3
0
/*
** Traverse an ephemeron table and link it to proper list. Returns true
** iff any object was marked during this traversal (which implies that
** convergence has to continue). During propagation phase, keep table
** in 'grayagain' list, to be visited again in the atomic phase. In
** the atomic phase, if table has any white->white entry, it has to
** be revisited during ephemeron convergence (as that key may turn
** black). Otherwise, if it has any white key, table has to be cleared
** (in the atomic phase).
*/
static int traverseephemeron (global_State *g, Table *h) {
  int marked = 0;  /* true if an object is marked in this traversal */
  int hasclears = 0;  /* true if table has white keys */
  int hasww = 0;  /* true if table has entry "white-key -> white-value" */
  Node *n, *limit = gnodelast(h);
  unsigned int i;
  /* traverse array part */
  for (i = 0; i < h->sizearray; i++) {
    if (valiswhite(&h->array[i])) {
      marked = 1;
      reallymarkobject(g, gcvalue(&h->array[i]));
    }
  }
  /* traverse hash part */
  for (n = gnode(h, 0); n < limit; n++) {
    checkdeadkey(n);
    if (ttisnil(gval(n)))  /* entry is empty? */
      removeentry(n);  /* remove it */
    else if (iscleared(g, gkey(n))) {  /* key is not marked (yet)? */
      hasclears = 1;  /* table must be cleared */
      if (valiswhite(gval(n)))  /* value not marked yet? */
        hasww = 1;  /* white-white entry */
    }
    else if (valiswhite(gval(n))) {  /* value not marked yet? */
      marked = 1;
      reallymarkobject(g, gcvalue(gval(n)));  /* mark it now */
    }
  }
  /* link table into proper list */
  if (g->gcstate == GCSpropagate)
    linkgclist(h, g->grayagain);  /* must retraverse it in atomic phase */
  else if (hasww)  /* table has white->white entries? */
    linkgclist(h, g->ephemeron);  /* have to propagate again */
  else if (hasclears)  /* table has white keys? */
    linkgclist(h, g->allweak);  /* may have to clean white keys */
  return marked;
}
Beispiel #4
0
/*
** traverse one gray object, turning it to black (except for threads,
** which are always gray).
*/
static void propagatemark (global_State *g) {
    lu_mem size;
    GCObject *o = g->gray;
    lua_assert(isgray(o));
    gray2black(o);
    switch (o->tt) {
    case LUA_TTABLE: {
        Table *h = gco2t(o);
        g->gray = h->gclist;  /* remove from 'gray' list */
        size = traversetable(g, h);
        break;
    }
    case LUA_TLCL: {
        LClosure *cl = gco2lcl(o);
        g->gray = cl->gclist;  /* remove from 'gray' list */
        size = traverseLclosure(g, cl);
        break;
    }
    case LUA_TCCL: {
        CClosure *cl = gco2ccl(o);
        g->gray = cl->gclist;  /* remove from 'gray' list */
        size = traverseCclosure(g, cl);
        break;
    }
    case LUA_TTHREAD: {
        lua_State *th = gco2th(o);
        g->gray = th->gclist;  /* remove from 'gray' list */
        linkgclist(th, g->grayagain);  /* insert into 'grayagain' list */
        black2gray(o);
        size = traversethread(g, th);
        break;
    }
    case LUA_TPROTO: {
        Proto *p = gco2p(o);
        g->gray = p->gclist;  /* remove from 'gray' list */
        size = traverseproto(g, p);
        break;
    }
    default:
        lua_assert(0);
        return;
    }
    g->GCmemtrav += size;
}
Beispiel #5
0
static lu_mem traversetable (global_State *g, Table *h) {
  const char *weakkey, *weakvalue;
  const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
  markobjectN(g, h->metatable);
  if (mode && ttisstring(mode) &&  /* is there a weak mode? */
      ((weakkey = strchr(svalue(mode), 'k')),
       (weakvalue = strchr(svalue(mode), 'v')),
       (weakkey || weakvalue))) {  /* is really weak? */
    black2gray(h);  /* keep table gray */
    if (!weakkey)  /* strong keys? */
      traverseweakvalue(g, h);
    else if (!weakvalue)  /* strong values? */
      traverseephemeron(g, h);
    else  /* all weak */
      linkgclist(h, g->allweak);  /* nothing to traverse now */
  }
  else  /* not weak */
    traversestrongtable(g, h);
  return sizeof(Table) + sizeof(TValue) * h->sizearray +
                         sizeof(Node) * cast(size_t, sizenode(h));
}
Beispiel #6
0
/*
** barrier that moves collector backward, that is, mark the black object
** pointing to a white object as gray again.
*/
void luaC_barrierback_ (lua_State *L, Table *t) {
  global_State *g = G(L);
  lua_assert(isblack(t) && !isdead(g, t));
  black2gray(t);  /* make table gray (again) */
  linkgclist(t, g->grayagain);
}