Example #1
0
static int traversetable (global_State *g, Table *h) {
  const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
  markobject(g, h->metatable);
  if (mode && ttisstring(mode)) {  /* is there a weak mode? */
    int weakkey = (strchr(svalue(mode), 'k') != NULL);
    int weakvalue = (strchr(svalue(mode), 'v') != NULL);
    if (weakkey || weakvalue) {  /* is really weak? */
      black2gray(obj2gco(h));  /* keep table gray */
      if (!weakkey) {  /* strong keys? */
        traverseweakvalue(g, h);
        return TRAVCOST + sizenode(h);
      }
      else if (!weakvalue) {  /* strong values? */
        traverseephemeron(g, h);
        return TRAVCOST + h->sizearray + sizenode(h);
      }
      else {
        linktable(h, &g->allweak);  /* nothing to traverse now */
        return TRAVCOST;
      }
    }  /* else go through */
  }
  traversestrongtable(g, h);
  return TRAVCOST + h->sizearray + (2 * sizenode(h));
}
Example #2
0
static void traverseweakvalue (global_State *g, Table *h) {
	Node *n, *limit = gnodelast(h);
	/* if there is array part, assume it may have white values (do not
	 traverse it just to check) */
	int hasclears = (h->sizearray > 0);
	for (n = gnode(h, 0); n < limit; n++) {
	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 (hasclears)
	linktable(h, &g->weak);  /* has to be cleared later */
	else  /* no white values */
	linktable(h, &g->grayagain);  /* no need to clean */
}
Example #3
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) {
	lu_mem size;
	white2gray(o);
	switch (gch(o)->tt) {
	case LUA_TSHRSTR:
	case LUA_TLNGSTR: {
		size = sizestring(gco2ts(o));
		break;  /* nothing else to mark; make it black */
	}
	case LUA_TUSERDATA: {
		Table *mt = gco2u(o)->metatable;
		markobject(g, mt);
		markobject(g, gco2u(o)->env);
		size = sizeudata(gco2u(o));
		break;
	}
	case LUA_TUPVAL: {
		UpVal *uv = gco2uv(o);
		markvalue(g, uv->v);
		if (uv->v != &uv->u.value)  /* open? */
		return;  /* open upvalues remain gray */
		size = sizeof(UpVal);
		break;
	}
	case LUA_TLCL: {
		gco2lcl(o)->gclist = g->gray;
		g->gray = o;
		return;
	}
	case LUA_TCCL: {
		gco2ccl(o)->gclist = g->gray;
		g->gray = o;
		return;
	}
	case LUA_TTABLE: {
		linktable(gco2t(o), &g->gray);
		return;
	}
	case LUA_TTHREAD: {
		gco2th(o)->gclist = g->gray;
		g->gray = o;
		return;
	}
	case LUA_TPROTO: {
		gco2p(o)->gclist = g->gray;
		g->gray = o;
		return;
	}
	default: lua_assert(0); return;
	}
	gray2black(o);
	g->GCmemtrav += size;
}
Example #4
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 (gch(o)->tt) {
    case LUA_TSHRSTR:
    case LUA_TLNGSTR: {
      gray2black(o);
      g->GCmemtrav += sizestring(gco2ts(o));
      break;
    }
    case LUA_TUSERDATA: {
      TValue uvalue;
      markobject(g, gco2u(o)->metatable);  /* mark its metatable */
      gray2black(o);
      g->GCmemtrav += sizeudata(gco2u(o));
      getuservalue(g->mainthread, rawgco2u(o), &uvalue);
      if (valiswhite(&uvalue)) {  /* markvalue(g, &uvalue); */
        o = gcvalue(&uvalue);
        goto reentry;
      }
      break;
    }
    case LUA_TLCL: {
      gco2lcl(o)->gclist = g->gray;
      g->gray = o;
      break;
    }
    case LUA_TCCL: {
      gco2ccl(o)->gclist = g->gray;
      g->gray = o;
      break;
    }
    case LUA_TTABLE: {
      linktable(gco2t(o), &g->gray);
      break;
    }
    case LUA_TTHREAD: {
      gco2th(o)->gclist = g->gray;
      g->gray = o;
      break;
    }
    case LUA_TPROTO: {
      gco2p(o)->gclist = g->gray;
      g->gray = o;
      break;
    }
    default: lua_assert(0); break;
  }
}
Example #5
0
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 prop = 0;  /* true if table has entry "white-key -> white-value" */
	Node *n, *limit = gnodelast(h);
	int i;
	/* traverse array part (numeric keys are 'strong') */
	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? */
		prop = 1;  /* must propagate again */
	}
	else if (valiswhite(gval(n))) {  /* value not marked yet? */
		marked = 1;
		reallymarkobject(g, gcvalue(gval(n)));  /* mark it now */
	}
	}
	if (prop)
	linktable(h, &g->ephemeron);  /* have to propagate again */
	else if (hasclears)  /* does table have white keys? */
	linktable(h, &g->allweak);  /* may have to clean white keys */
	else  /* no white keys */
	linktable(h, &g->grayagain);  /* no need to clean */
	return marked;
}
Example #6
0
/*
** mark an object. Userdata and closed upvalues are visited and turned
** black here. Strings remain gray (it is the same as making them
** black). 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) {
  lua_assert(iswhite(o) && !isdead(g, o));
  white2gray(o);
  switch (gch(o)->tt) {
    case LUA_TSTRING: {
      return;  /* for strings, gray is as good as black */
    }
    case LUA_TUSERDATA: {
      Table *mt = gco2u(o)->metatable;
      markobject(g, mt);
      markobject(g, gco2u(o)->env);
      gray2black(o);  /* all pointers marked */
      return;
    }
    case LUA_TUPVAL: {
      UpVal *uv = gco2uv(o);
      markvalue(g, uv->v);
      if (uv->v == &uv->u.value)  /* closed? (open upvalues remain gray) */
        gray2black(o);  /* make it black */
      return;
    }
    case LUA_TFUNCTION: {
      gco2cl(o)->c.gclist = g->gray;
      g->gray = o;
      break;
    }
    case LUA_TTABLE: {
      linktable(gco2t(o), &g->gray);
      break;
    }
    case LUA_TTHREAD: {
      gco2th(o)->gclist = g->gray;
      g->gray = o;
      break;
    }
    case LUA_TPROTO: {
      gco2p(o)->gclist = g->gray;
      g->gray = o;
      break;
    }
    default: lua_assert(0);
  }
}
Example #7
0
static lu_mem traversetable (global_State *g, Table *h) {
	const char *weakkey, *weakvalue;
	const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
	markobject(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(obj2gco(h));  /* keep table gray */
	if (!weakkey)  /* strong keys? */
		traverseweakvalue(g, h);
	else if (!weakvalue)  /* strong values? */
		traverseephemeron(g, h);
	else  /* all weak */
		linktable(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));
}