Example #1
0
/* Upvalues are tricky. Here's why.
 *
 * A particular upvalue may be either "open", in which case its member v
 * points into a thread's stack, or "closed" in which case it points to the
 * upvalue itself. An upvalue is closed under any of the following conditions:
 * -- The function that initially declared the variable "local" returns
 * -- The thread in which the closure was created is garbage collected 
 *
 * To make things wackier, just because a thread is reachable by Lua doesn't
 * mean it's in our root set. We need to be able to treat an open upvalue
 * from an unreachable thread as a closed upvalue.
 *
 * The solution:
 * (a) For the purposes of persisting, don't indicate whether an upvalue is
 * closed or not.
 * (b) When unpersisting, pretend that all upvalues are closed.
 * (c) When persisting, persist all open upvalues referenced by a thread
 * that is persisted, and tag each one with the corresponding stack position
 * (d) When unpersisting, "reopen" each of these upvalues as the thread is
 * unpersisted
 */
static void persistupval(PersistInfo *pi) {
	/* perms reftbl ... upval */
	UpVal *uv = toupval(pi->L, -1);

	luaA_pushobject(pi->L, uv->v);
	/* perms reftbl ... upval obj */
	persist(pi);
	lua_pop(pi->L, 1);
	/* perms reftbl ... upval */
}
Example #2
0
/* The GC is not fond of finding upvalues in tables. We get around this
 * during persistence using a weakly keyed table, so that the GC doesn't
 * bother to mark them. This won't work in unpersisting, however, since
 * if we make the values weak they'll be collected (since nothing else
 * references them). Our solution, during unpersisting, is to represent
 * upvalues as dummy functions, each with one upvalue. */
static void boxupval(lua_State *L) {
	/* ... upval */
	LClosure *lcl;
	UpVal *uv;

	uv = toupval(L, -1);
	lua_pop(L, 1);
	/* ... */
	lcl = (LClosure*)luaF_newLclosure(L, 1, &L->_gt);
	pushclosure(L, (Closure*)lcl);
	/* ... func */
	lcl->p = makefakeproto(L, 1);
	lcl->upvals[0] = uv;
}
Example #3
0
/* Upvalues are tricky. Here's why.
 *
 * A particular upvalue may be either "open", in which case its member v
 * points into a thread's stack, or "closed" in which case it points to the
 * upvalue itself. An upvalue is closed under any of the following conditions:
 * -- The function that initially declared the variable "local" returns
 * -- The thread in which the closure was created is garbage collected
 *
 * To make things wackier, just because a thread is reachable by Lua doesn't
 * mean it's in our root set. We need to be able to treat an open upvalue
 * from an unreachable thread as a closed upvalue.
 *
 * The solution:
 * (a) For the purposes of persisting, don't indicate whether an upvalue is
 * closed or not.
 * (b) When unpersisting, pretend that all upvalues are closed.
 * (c) When persisting, persist all open upvalues referenced by a thread
 * that is persisted, and tag each one with the corresponding stack position
 * (d) When unpersisting, "reopen" each of these upvalues as the thread is
 * unpersisted
 */
static void persistupval(PersistInfo *pi)
{
					/* perms reftbl ... upval */
	UpVal *uv = toupval(pi->L, -1);
	lua_checkstack(pi->L, 1);

	/* We can't permit the upval to linger around on the stack, as Lua
	* will bail if its GC finds it. */

	lua_pop(pi->L, 1);
					/* perms reftbl ... */
	LIF(A,pushobject)(pi->L, uv->v);
					/* perms reftbl ... obj */
	persist(pi);
					/* perms reftbl ... obj */
}
Example #4
0
static void unpersistfunction(int ref, UnpersistInfo *upi) {
	/* perms reftbl ... */
	LClosure *lcl;
	int i;
	lu_byte nupvalues;

	verify(luaZ_read(&upi->zio, &nupvalues, sizeof(lu_byte)) == 0);

	lcl = (LClosure*)luaF_newLclosure(upi->L, nupvalues, &upi->L->_gt);
	pushclosure(upi->L, (Closure*)lcl);

	/* perms reftbl ... func */
	/* Put *some* proto in the closure, before the GC can find it */
	lcl->p = makefakeproto(upi->L, nupvalues);

	/* Also, we need to temporarily fill the upvalues */
	lua_pushnil(upi->L);
	/* perms reftbl ... func nil */
	for(i=0; i<nupvalues; i++) {
		lcl->upvals[i] = makeupval(upi->L, -1);
	}
	lua_pop(upi->L, 1);
	/* perms reftbl ... func */

	/* I can't see offhand how a function would ever get to be self-
	 * referential, but just in case let's register it early */
	registerobject(ref, upi);

	/* Now that it's safe, we can get the real proto */
	unpersist(upi);
	/* perms reftbl ... func proto? */
	lua_assert(lua_type(upi->L, -1) == LUA_TPROTO);
	/* perms reftbl ... func proto */
	lcl->p = toproto(upi->L, -1);
	lua_pop(upi->L, 1);
	/* perms reftbl ... func */

	for(i=0; i<nupvalues; i++) {
		/* perms reftbl ... func */
		unpersist(upi);
		/* perms reftbl ... func func2 */
		unboxupval(upi->L);
		/* perms reftbl ... func upval */
		lcl->upvals[i] = toupval(upi->L, -1);
		lua_pop(upi->L, 1);
		/* perms reftbl ... func */
	}
	/* perms reftbl ... func */

	/* Finally, the fenv */
	unpersist(upi);
	/* perms reftbl ... func fenv/nil? */
	lua_assert(lua_type(upi->L, -1) == LUA_TNIL ||
	           lua_type(upi->L, -1) == LUA_TTABLE);
	/* perms reftbl ... func fenv/nil */
	if(!lua_isnil(upi->L, -1)) {
		/* perms reftbl ... func fenv */
		lua_setfenv(upi->L, -2);
		/* perms reftbl ... func */
	} else {
		/* perms reftbl ... func nil */
		lua_pop(upi->L, 1);
		/* perms reftbl ... func */
	}
	/* perms reftbl ... func */
}
Example #5
0
static void unpersistthread(int ref, UnpersistInfo *upi) {
	/* perms reftbl ... */
	lua_State *L2;
	L2 = lua_newthread(upi->L);
	/* L1: perms reftbl ... thr */
	/* L2: (empty) */
	registerobject(ref, upi);

	/* First, deserialize the object stack. */
	{
		int i, stacksize;
		verify(luaZ_read(&upi->zio, &stacksize, sizeof(int)) == 0);
		luaD_growstack(L2, stacksize);
		/* Make sure that the first stack element (a nil, representing
		 * the imaginary top-level C function) is written to the very,
		 * very bottom of the stack */
		L2->top--;
		for(i=0; i<stacksize; i++) {
			unpersist(upi);
			/* L1: perms reftbl ... thr obj* */
		}
		lua_xmove(upi->L, L2, stacksize);
		/* L1: perms reftbl ... thr */
		/* L2: obj* */
	}

	/* Now, deserialize the CallInfo stack. */
	{
		int i, numframes;
		verify(luaZ_read(&upi->zio, &numframes, sizeof(int)) == 0);
		luaD_reallocCI(L2,numframes*2);
		for(i=0; i<numframes; i++) {
			CallInfo *ci = L2->base_ci + i;
			int stackbase, stacktop, pc;
			verify(luaZ_read(&upi->zio, &stackbase, sizeof(int)) == 0);
			verify(luaZ_read(&upi->zio, &stacktop, sizeof(int)) == 0);
			verify(luaZ_read(&upi->zio, &pc, sizeof(int)) == 0);
			verify(luaZ_read(&upi->zio, &(ci->state), sizeof(int)) == 0);

			ci->base = L2->stack+stackbase;
			ci->top = L2->stack+stacktop;
			if(!(ci->state & CI_C)) {
				ci->u.l.savedpc = ci_func(ci)->l.p->code + pc;
			}
			ci->u.l.tailcalls = 0;
			/* Update the pointer each time, to keep the GC
			 * happy*/
			L2->ci = ci;
		}
	}
	/* L1: perms reftbl ... thr */
	{
		int stackbase, stacktop;
		verify(luaZ_read(&upi->zio, &stackbase, sizeof(int)) == 0);
		verify(luaZ_read(&upi->zio, &stacktop, sizeof(int)) == 0);
		L2->base = L2->stack + stackbase;
		L2->top = L2->stack + stacktop;
	}
	/* Finally, "reopen" upvalues (see persistupval() for why) */
	{
		UpVal* uv;
		GCObject **nextslot = &L2->openupval;
		while(1) {
			int stackpos;
			unpersist(upi);
			/* perms reftbl ... thr uv/nil */
			if(lua_isnil(upi->L, -1)) {
				/* perms reftbl ... thr nil */
				lua_pop(upi->L, 1);
				/* perms reftbl ... thr */
				break;
			}
			/* perms reftbl ... thr boxeduv */
			unboxupval(upi->L);
			/* perms reftbl ... thr uv */
			uv = toupval(upi->L, -1);
			lua_pop(upi->L, 1);
			/* perms reftbl ... thr */

			verify(luaZ_read(&upi->zio, &stackpos, sizeof(int)) == 0);
			uv->v = L2->stack + stackpos;
			gcunlink(upi->L, valtogco(uv));
			uv->marked = 1;
			*nextslot = valtogco(uv);
			nextslot = &uv->next;
		}
		*nextslot = NULL;
	}
}