lua-users home
lua-l archive

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


I wrote a small tool to reload lua modules online. ( https://github.com/cloudwu/luareload )

It can load lua modules already loaded before, and replace all the old functions in VM with new version.
I found debug.upvalueid() and debug.upvaluejoin() is not enough. For example, It can't handle the function like this :

-- old version --
local mod = {}

local a

function mod.foo()
  return function ()
    return a
  end
end

return mod
---new version ---
local mod = {}

local a

function mod.foo()
  return function ()
    return a * 2
  end
end

return mod
-------------

The anonymous function returns by mod.foo belongs this module. But there is no way to replace
'function() return a end' to 'function() return a*2 end' , because after reloading the module, the new version anonymous function is not exist, yet.

I suggest add a new api to create a function from prototype of internal function. ( https://github.com/cloudwu/luareload/blob/proto/clonefunc.c )

------
int lclone(lua_State *L) {
if (!lua_isfunction(L, 1) || lua_iscfunction(L,1))
return luaL_error(L, "Need lua function");
const LClosure *c = lua_topointer(L,1);
int n = luaL_optinteger(L, 2, 0);
if (n < 0 || n > c->p->sizep)
return 0;
luaL_checkstack(L, 1, NULL);
Proto *p;
if (n==0) {
p = c->p;
} else {
p = c->p->p[n-1];
}

lua_lock(L);
LClosure *cl = luaF_newLclosure(L, p->sizeupvalues);
luaF_initupvals(L, cl);
cl->p = p;
setclLvalue(L, L->top++, cl);
lua_unlock(L);

return 1;
}
-----

And we can use 'clone(mod.foo, 1)' to create the function with the prototype of mod.foo (the new version of that anonymous function), and then join the upvalues of the old anonymous function. 

See an example :  https://github.com/cloudwu/luareload/tree/proto