Ejemplo n.º 1
0
    int writeObjectRaw()
    {
        lua_State *L = m_L;
        uint8_t iType;

        // Save the index to the cache
        lua_pushvalue(L, 2);
        lua_pushnumber(L, (lua_Number)(m_iNextIndex++));
        lua_settable(L, 1);

        // Lookup the object in the permanents table
        lua_pushvalue(L, 2);
        lua_gettable(L, luaT_upvalueindex(1));
        if(lua_type(L, -1) != LUA_TNIL)
        {
            // Object is in the permanents table.

            uint8_t iType = PERSIST_TPERMANENT;
            writeByteStream(&iType, 1);

            // Replace self's environment with self (for call to writeStackObject)
            lua_pushvalue(L, luaT_upvalueindex(2));
            lua_replace(L, 1);

            // Write the key corresponding to the permanent object
            writeStackObject(-1);
        }
        else
        {
            // Object is not in the permanents table.
            lua_pop(L, 1);

            switch(lua_type(L, 2))
            {
            // LUA_TNIL handled in writeStackObject
            // LUA_TBOOLEAN handled in writeStackObject
            // LUA_TNUMBER handled in writeStackObject

            case LUA_TSTRING: {
                iType = LUA_TSTRING;
                writeByteStream(&iType, 1);
                // Strings are simple: length and then bytes (not null terminated)
                size_t iLength;
                const char *sString = lua_tolstring(L, 2, &iLength);
                writeVUInt(iLength);
                writeByteStream(reinterpret_cast<const uint8_t*>(sString), iLength);
                break; }

            case LUA_TTABLE: {
                // Replace self's environment with self (for calls to writeStackObject)
                lua_pushvalue(L, luaT_upvalueindex(2));
                lua_replace(L, 1);

                // Save env and insert prior to table
                lua_getfenv(L, 1);
                lua_insert(L, 2);

                int iTable = 3; table_reentry:

                // Handle the metatable
                if(lua_getmetatable(L, iTable))
                {
                    iType = PERSIST_TTABLE_WITH_META;
                    writeByteStream(&iType, 1);
                    writeStackObject(-1);
                    lua_pop(L, 1);
                }
                else
                {
                    iType = LUA_TTABLE;
                    writeByteStream(&iType, 1);
                }

                // Write the children as key, value pairs
                lua_pushnil(L);
                while(lua_next(L, iTable))
                {
                    writeStackObject(-2);
                    // The naive thing to do now would be writeStackObject(-1)
                    // but this can easily lead to Lua's C call stack limit
                    // being hit. To reduce the likelyhood of this happening,
                    // we check to see if about to write another table.
                    if(lua_type(L, -1) == LUA_TTABLE)
                    {
                        lua_pushvalue(L, -1);
                        lua_rawget(L, 2);
                        lua_pushvalue(L, -2);
                        lua_gettable(L, luaT_upvalueindex(1));
                        if(lua_isnil(L, -1) && lua_isnil(L, -2))
                        {
                            lua_pop(L, 2);
                            lua_checkstack(L, 10);
                            iTable += 2;
                            lua_pushvalue(L, iTable);
                            lua_pushnumber(L, (lua_Number)(m_iNextIndex++));
                            lua_settable(L, 2);
                            goto table_reentry; table_resume:
                            iTable -= 2;
                        }
                        else
                        {
                            lua_pop(L, 2);
                            writeStackObject(-1);
                        }
                    }
                    else
                        writeStackObject(-1);
                    lua_pop(L, 1);
                }

                // Write a nil to mark the end of the children (as nil is the
                // only value which cannot be used as a key in a table).
                iType = LUA_TNIL;
                writeByteStream(&iType, 1);
                if(iTable != 3)
                    goto table_resume;
                break; }

            case LUA_TFUNCTION:
                if(lua_iscfunction(L, 2))
                {
                    setErrorObject(2);
                    setError("Cannot persist C functions");
                }
                else
                {
                    iType = LUA_TFUNCTION;
                    writeByteStream(&iType, 1);

                    // Replace self's environment with self (for calls to writeStackObject)
                    lua_pushvalue(L, luaT_upvalueindex(2));
                    lua_replace(L, 1);

                    // Write the prototype (the part of a function which is common across
                    // multiple closures - see LClosure / Proto in Lua's lobject.h).
                    lua_Debug proto_info;
                    lua_pushvalue(L, 2);
                    lua_getinfo(L, ">Su", &proto_info);
                    writePrototype(&proto_info, 2);

                    // Write the values of the upvalues
                    // If available, also write the upvalue IDs (so that in
                    // the future, we could hypothetically rejoin shared
                    // upvalues). An ID is just an opaque sequence of bytes.
                    writeVUInt(proto_info.nups);
#if LUA_VERSION_NUM >= 502
                    writeVUInt(sizeof(void*));
#else
                    writeVUInt(0);
#endif
                    for(int i = 1; i <= proto_info.nups; ++i)
                    {
                        lua_getupvalue(L, 2, i);
                        writeStackObject(-1);
#if LUA_VERSION_NUM >= 502
                        void *pUpvalueID = lua_upvalueid(L, 2, i);
                        writeByteStream((uint8_t*)&pUpvalueID, sizeof(void*));
#endif
                    }

                    // Write the environment table
                    lua_getfenv(L, 2);
                    writeStackObject(-1);
                    lua_pop(L, 1);
                }
                break;

            case LUA_TUSERDATA:
                if(!_checkThatUserdataCanBeDepersisted(2))
                    break;

                // Replace self's environment with self (for calls to writeStackObject)
                lua_pushvalue(L, luaT_upvalueindex(2));
                lua_replace(L, 1);

                // Write type, metatable, and then environment
                iType = LUA_TUSERDATA;
                writeByteStream(&iType, 1);
                writeStackObject(-1);
                lua_getfenv(L, 2);
                writeStackObject(-1);
                lua_pop(L, 1);

                // Write the raw data
                if(lua_type(L, -1) == LUA_TTABLE)
                {
                    lua_getfield(L, -1, "__persist");
                    if(lua_isnil(L, -1))
                        lua_pop(L, 1);
                    else
                    {
                        lua_pushvalue(L, 2);
                        lua_pushvalue(L, luaT_upvalueindex(2));
                        lua_call(L, 2, 0);
                    }
                }
                writeVUInt((uint64_t)0x42); // sync marker
                break;

            default:
                setError(lua_pushfstring(L, "Cannot persist %s values", luaL_typename(L, 2)));
                break;
            }
        }
        lua_pushnumber(L, 0);
        return 1;
    }
Ejemplo n.º 2
0
static int db_upvalueid (lua_State *L) {
  int n = checkupval(L, 1, 2);
  lua_pushlightuserdata(L, lua_upvalueid(L, 1, n));
  return 1;
}
Ejemplo n.º 3
0
void * LuaDebug::UpvalueID(int funcindex, int n) const
{
	return lua_upvalueid(L(), funcindex, n);
}