Upvalues when dump/load a function?

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Upvalues when dump/load a function?

Tim Hill
Would anyone like to comment on the behavior of this code? It prints "local x" and "nil", which is probably correct, but odd. I understand that "load()" compiles code in a global context, but when I have the output of string.dump() its not really being compiled again, is it? It's just packaged VM bytecodes. Given that, what happens to the upvalues? The ref manual for 5.2 simply says "with new upvalues" when a dumped function is loaded, but makes no mention of what this means, and of course in the code sample there ARE no upvalues to bind to the function anyway.

x = "global x"

do
        local x = "local x"
        function foo() print(x) end
end

foo()
sf = string.dump(foo)
f2 = load(sf, "", "bt", _ENV)
f2()


Reply | Threaded
Open this post in threaded view
|

Re: Upvalues when dump/load a function?

Patrick Rapin
A closure is composed of two elements: a (reference to a) piece of
code in bytecode format and (references to) values for outer local
variables (upvalues).
The string.dump function only dumps the piece of code and *not* the
values stored in the upvalues.
So when you load them again, upvalues are logically initialized to nil.

Using debug.setupvalue it is possible to save and restore upvalues in code dump.
This is what my serialization function "DataDumper" [1] is able to do
(for Lua 5.1).
It outputs the following code for your example (notice that it is
quite complex) :

> =DataDumper(foo)
local closures = {}
local function closure(t)
  closures[#closures+1] = t
  t[1] = assert(loadstring(t[1]))
  return t[1]
end
local t = closure {
  "←LuaQ\000☺♦\000\000\000\000=stdin\000♠\000\000\000♠\000\000\000☺\000 ... ",
  "local x"
}
for _,t in pairs(closures) do
  for i = 2,#t do
    debug.setupvalue(t[1], i-1, t[i])
  end
end
return t

[1] http://lua-users.org/wiki/DataDumper or https://gist.github.com/766518