diff --git a/src/method.c b/src/method.c index c33b343742dc8..46a4f5bc4d56c 100644 --- a/src/method.c +++ b/src/method.c @@ -958,6 +958,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); diff --git a/stdlib/Serialization/src/Serialization.jl b/stdlib/Serialization/src/Serialization.jl index 3c4152bf10598..1b25c59bf3cdf 100644 --- a/stdlib/Serialization/src/Serialization.jl +++ b/stdlib/Serialization/src/Serialization.jl @@ -8,6 +8,7 @@ Provide serialization of Julia objects via the functions module Serialization import Base: Bottom, unsafe_convert +import Base.ScopedValues: ScopedValue, with import Core: svec, SimpleVector using Base: unaliascopy, unwrap_unionall, require_one_based_indexing, ntupleany using Core.IR @@ -28,6 +29,8 @@ end Serializer(io::IO) = Serializer{typeof(io)}(io) +const current_module = ScopedValue{Union{Nothing,Module}}(nothing) + ## serializing values ## const n_int_literals = 33 @@ -1064,7 +1067,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 + with(current_module => mod) do + 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 @@ -1078,7 +1084,9 @@ function deserialize(s::AbstractSerializer, ::Type{Method}) elseif format_version(s) >= 17 purity = UInt16(deserialize(s)::UInt8) end - template = deserialize(s) + with(current_module => mod) do + template = deserialize(s) + end else template = template_or_is_opaque end @@ -1182,6 +1190,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) @@ -1200,6 +1224,9 @@ function deserialize(s::AbstractSerializer, ::Type{CodeInfo}) end end end + if current_module[] !== nothing + map!(x->symbol_to_globalref(x, current_module[]), code) + end _x = deserialize(s) have_debuginfo = _x isa Core.DebugInfo if have_debuginfo @@ -1248,6 +1275,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 @@ -1258,7 +1288,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 diff --git a/stdlib/Serialization/test/runtests.jl b/stdlib/Serialization/test/runtests.jl index f1b83ca947c7e..e341c6e3eb9ec 100644 --- a/stdlib/Serialization/test/runtests.jl +++ b/stdlib/Serialization/test/runtests.jl @@ -1,6 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license using Test, Random, Serialization, Base64 +using Base.ScopedValues: with # Check that serializer hasn't gone out-of-frame @test Serialization.sertag(Symbol) == 1 @@ -661,3 +662,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 + Core.eval(Main, with(Serialization.current_module => Main) do + deserialize(IOBuffer(base64decode(f_data))) + end) + @test @invokelatest(Main.f111_to_112(16)) == 256 + end +end