lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


I want to be able to serialize functions that share the same upvalue
and then restore the relationship on deserialization. This post from a
few years ago has a patch for vanilla Lua to do the same thing, and
more information on the problem:

http://lua-users.org/lists/lua-l/2008-02/msg01173.html

I went ahead and patched LuaJIT 2 (beta10) to do this (the patch and a
very simple test is attached). It seems to work, but since I am not
familiar with the internals of LuaJIT, I am not confident that the
changes are completely correct. I am assuming that lua_shareupvalue is
only called on lua functions right after deserialization and before
they are first invoked.

Can anyone comment on whether this code should work in general, and on
any issues I might be missing?

Thanks!

Zach
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char * luainput = 
"local a = 0\n"
"function up()\n"
"    a = a + 1\n"
"end\n"
"function get()\n"
"    print(a)\n"
"end\n"
"return up,get\n";


char buf[1024 * 1024];
size_t bsz = 0;
int dumptobuf(lua_State * L, const void * p, size_t sz, void * ud) {
    assert(sz < 1024 * 1024);
    memcpy(buf+bsz,p,sz);
    bsz += sz;
    return 0;
}

int main() {
    lua_State * L = luaL_newstate();
    luaL_openlibs(L);
    if(luaL_dostring(L,luainput)) {
        fprintf(stderr,"%s\n",luaL_checkstring(L,-1));
        return 1;
    }
    
    {
        const void * uv0 = lua_getupvalueaddr(L,-1,1);
        const void * uv1 = lua_getupvalueaddr(L,-2,1);    
        printf("upvalues (L) %p %p\n", uv0, uv1);
    }
    
    lua_State * L2 = luaL_newstate();
    luaL_openlibs(L2);
    
    assert( 0 == lua_dump(L, dumptobuf,NULL) );
    
    assert( 0 == luaL_loadbuffer(L2,buf,bsz,"get") );
    
    bsz = 0;
    lua_pop(L,1);
    assert(lua_dump(L, dumptobuf,NULL) == 0);
    assert(0 == luaL_loadbuffer(L2,buf,bsz,"up"));
    
    lua_pushnumber(L2,42);
    assert(NULL != lua_setupvalue(L2,-2,1));
    
    {
        const void * uv0 = lua_getupvalueaddr(L2,-1,1);
        const void * uv1 = lua_getupvalueaddr(L2,-2,1);    
        printf("upvalues (L2 before) %p %p\n", uv0, uv1);
    }
    
    assert(0 == lua_shareupvalue(L2,-1,1,-2,1));
    
    {
        const void * uv0 = lua_getupvalueaddr(L2,-1,1);
        const void * uv1 = lua_getupvalueaddr(L2,-2,1);    
        printf("upvalues (L2 after) %p %p\n", uv0, uv1);
    }
    for(int i = 0; i < 10; i++) {
        lua_pushvalue(L2,-2);
        lua_pushvalue(L2,-2);
        lua_call(L2,0,0);
        lua_call(L2,0,0);
    }
    
    return 0;
}

Attachment: upvalues.patch
Description: Binary data