Skip to content

fix serializer compat with CodeInfos from v1.11 #58650

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/method.c
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,9 @@ JL_DLLEXPORT void jl_method_set_source(jl_method_t *m, jl_code_info_t *src)
}
src = jl_copy_code_info(src);
src->isva = m->isva; // TODO: It would be nice to reverse this
// If nargs hasn't been set yet, do it now. This can happen if an old CodeInfo is deserialized.
if (src->nargs == 0)
src->nargs = m->nargs;
assert(m->nargs == src->nargs);
src->code = copy;
jl_gc_wb(src, copy);
Expand Down
49 changes: 45 additions & 4 deletions stdlib/Serialization/src/Serialization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,25 @@ mutable struct Serializer{I<:IO} <: AbstractSerializer
pending_refs::Vector{Int}
known_object_data::Dict{UInt64,Any}
version::Int
Serializer{I}(io::I) where I<:IO = new(io, 0, IdDict(), Int[], Dict{UInt64,Any}(), ser_version)
current_module::Union{Nothing,Module}
Serializer{I}(io::I) where I<:IO = new(io, 0, IdDict(), Int[], Dict{UInt64,Any}(), ser_version, nothing)
end

Serializer(io::IO) = Serializer{typeof(io)}(io)

macro withmodule(s, m, code)
s, m, code = esc(s), esc(m), esc(code)
quote
_prev = ($s).current_module
($s).current_module = $m
try
$code
finally
($s).current_module = _prev
end
end
end

## serializing values ##

const n_int_literals = 33
Expand Down Expand Up @@ -1064,7 +1078,10 @@ function deserialize(s::AbstractSerializer, ::Type{Method})
nospecializeinfer = false
constprop = 0x00
purity = 0x0000
template_or_is_opaque = deserialize(s)
local template_or_is_opaque, template
@withmodule s mod begin
template_or_is_opaque = deserialize(s)
end
if isa(template_or_is_opaque, Bool)
is_for_opaque_closure = template_or_is_opaque
if format_version(s) >= 24
Expand All @@ -1078,7 +1095,9 @@ function deserialize(s::AbstractSerializer, ::Type{Method})
elseif format_version(s) >= 17
purity = UInt16(deserialize(s)::UInt8)
end
template = deserialize(s)
@withmodule s mod begin
template = deserialize(s)
end
else
template = template_or_is_opaque
end
Expand Down Expand Up @@ -1182,6 +1201,22 @@ function deserialize(s::AbstractSerializer, ::Type{PhiNode})
return PhiNode(edges, values)
end

# v1.12 disallows bare symbols in IR, but older CodeInfos might still have them
function symbol_to_globalref(@nospecialize(x), m::Module)
mapper(@nospecialize(x)) = symbol_to_globalref(x, m)
if x isa Symbol
return GlobalRef(m, x)
elseif x isa Expr
return Expr(x.head, map(mapper, x.args)...)
elseif x isa ReturnNode
return ReturnNode(mapper(x.val))
elseif x isa GotoIfNot
return GotoIfNot(mapper(x.cond), x.dest)
else
return x
end
end

function deserialize(s::AbstractSerializer, ::Type{CodeInfo})
ci = ccall(:jl_new_code_info_uninit, Ref{CodeInfo}, ())
deserialize_cycle(s, ci)
Expand All @@ -1200,6 +1235,9 @@ function deserialize(s::AbstractSerializer, ::Type{CodeInfo})
end
end
end
if s.current_module !== nothing
map!(x->symbol_to_globalref(x, s.current_module), code)
end
_x = deserialize(s)
have_debuginfo = _x isa Core.DebugInfo
if have_debuginfo
Expand Down Expand Up @@ -1248,6 +1286,9 @@ function deserialize(s::AbstractSerializer, ::Type{CodeInfo})
ci.slottypes = deserialize(s)
ci.rettype = deserialize(s)
ci.parent = deserialize(s)
if format_version(s) < 29 && ci.parent isa MethodInstance && ci.parent.def isa Method
ci.nargs = ci.parent.def.nargs
end
world_or_edges = deserialize(s)
pre_13 = isa(world_or_edges, Union{UInt, Int})
if pre_13
Expand All @@ -1258,7 +1299,7 @@ function deserialize(s::AbstractSerializer, ::Type{CodeInfo})
ci.min_world = deserialize(s)::UInt
ci.max_world = deserialize(s)::UInt
end
if format_version(s) >= 26
if format_version(s) >= 29
ci.method_for_inference_limit_heuristics = deserialize(s)
end
end
Expand Down
11 changes: 11 additions & 0 deletions stdlib/Serialization/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -661,3 +661,14 @@ end
@test_broken isempty(undoc)
@test undoc == [:AbstractSerializer, :Serializer]
end

# test method definitions from v1.11
if Int === Int64
let f_data = "N0pMGgQAAAAWAQEFdGh1bmsbFUbnFgEBBXRodW5rGxVG4DoWAQEGbWV0aG9kAQtmMTExX3RvXzExMhUABuABAAAA4BUAB+AAAAAAThVG4DQQAQxMaW5lSW5mb05vZGUfTptEH04BBE1haW5EAQ90b3AtbGV2ZWwgc2NvcGUBBG5vbmW+vhUAAd8V305GTk4JAQAAAAAAAAAJ//////////9MTExMAwADAAUAAAX//xYBAQZtZXRob2QsBwAWAlYkH06bRAEGVHlwZW9mLAcAFgNWJB9Om0QBBHN2ZWMo4iQfTptETxYBViQfTptEAQRzdmVjFgRWJB9Om0QBBHN2ZWMo4yjkGhfgAQRub25lFgMBBm1ldGhvZCwHACjlGxVG5AEBXhYDViQfTptElyQfTp5EAQNWYWzhFgFWKOEWBFYkH06eRAELbGl0ZXJhbF9wb3co4CXhKOI6KOMVAAbkAQAAAAEAAAABAAAAAQAAAAAAAADkFQAH5AAAAAAAAAAAAAAAAAAAAAAAAAAAThVG4DQsCwAfTgEETWFpbkQBBG5vbmUBBG5vbmW/vhUAAeGifRXhAAhORk5OCQEAAAAAAAAACf//////////TExMTAMAAwAFAAAF//86ThUABucBAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAAAAAOcVAAfnAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABOFUbgNCwLAB9OAQRNYWluRCwNAAEEbm9uZb6+FQAB3xXfTkZOTgkBAAAAAAAAAAn//////////0xMTEwDAAMABQAABf//"
@eval Main function f111_to_112 end
s = Serializer(IOBuffer(base64decode(f_data)))
s.current_module = Main
Core.eval(Main, deserialize(s))
@test @invokelatest(Main.f111_to_112(16)) == 256
end
end