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.
------
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.