Skip to content

Commit 480f923

Browse files
committed
ensure known_object_data is assigned before deserialize is called again
also reduce code duplication for easier maintenance ref #16091
1 parent e717ded commit 480f923

File tree

2 files changed

+37
-47
lines changed

2 files changed

+37
-47
lines changed

base/clusterserialize.jl

+17-35
Original file line numberDiff line numberDiff line change
@@ -9,45 +9,24 @@ type ClusterSerializer{I<:IO} <: AbstractSerializer
99
counter::Int
1010
table::ObjectIdDict
1111

12-
sent_objects::Dict{UInt64, Bool} # used by serialize (track objects sent)
12+
sent_objects::Set{UInt64} # used by serialize (track objects sent)
1313

14-
ClusterSerializer(io::I) = new(io, 0, ObjectIdDict(), Dict())
14+
ClusterSerializer(io::I) = new(io, 0, ObjectIdDict(), Set{UInt64}())
1515
end
1616
ClusterSerializer(io::IO) = ClusterSerializer{typeof(io)}(io)
1717

1818
function deserialize(s::ClusterSerializer, ::Type{TypeName})
19-
number, full_body_sent = deserialize(s)
20-
makenew = false
21-
known = haskey(known_object_data, number)
19+
full_body_sent = deserialize(s)
2220
if !full_body_sent
23-
if !known
24-
error("Expected object in cache. Not found.")
25-
else
26-
tn = known_object_data[number]::TypeName
21+
number = read(s.io, UInt64)
22+
tn = get(known_object_data, number, nothing)::TypeName
23+
if !haskey(object_numbers, tn)
24+
# setup reverse mapping for serialize
25+
object_numbers[tn] = number
2726
end
27+
deserialize_cycle(s, tn)
2828
else
29-
name = deserialize(s)
30-
mod = deserialize(s)
31-
if known
32-
tn = known_object_data[number]::TypeName
33-
elseif mod !== __deserialized_types__ && isdefined(mod, name)
34-
tn = getfield(mod, name).name
35-
# TODO: confirm somehow that the types match
36-
#warn(mod, ".", name, " isdefined, need not have been serialized")
37-
name = tn.name
38-
mod = tn.module
39-
else
40-
name = gensym()
41-
mod = __deserialized_types__
42-
tn = ccall(:jl_new_typename_in, Ref{TypeName}, (Any, Any), name, mod)
43-
makenew = true
44-
end
45-
end
46-
deserialize_cycle(s, tn)
47-
full_body_sent && deserialize_typename_body(s, tn, number, name, mod, makenew)
48-
!known && (known_object_data[number] = tn)
49-
if !haskey(object_numbers, tn)
50-
object_numbers[tn] = number
29+
tn = invoke(deserialize, (AbstractSerializer, Type{TypeName}), s, TypeName)
5130
end
5231
return tn
5332
end
@@ -57,15 +36,18 @@ function serialize(s::ClusterSerializer, t::TypeName)
5736
writetag(s.io, TYPENAME_TAG)
5837

5938
identifier = object_number(t)
60-
if !haskey(s.sent_objects, identifier)
61-
serialize(s, (identifier, true))
39+
if !(identifier in s.sent_objects)
40+
serialize(s, true)
41+
write(s.io, identifier)
6242
serialize(s, t.name)
6343
serialize(s, t.module)
6444
serialize_typename_body(s, t)
65-
s.sent_objects[identifier] = true
45+
push!(s.sent_objects, identifier)
6646
# println(t.module, ":", t.name, ", id:", identifier, " sent")
6747
else
68-
serialize(s, (identifier, false))
48+
serialize(s, false)
49+
write(s.io, identifier)
6950
# println(t.module, ":", t.name, ", id:", identifier, " NOT sent")
7051
end
52+
nothing
7153
end

base/serialize.jl

+20-12
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@ function serialize_typename_body(s::AbstractSerializer, t::TypeName)
419419
else
420420
writetag(s.io, UNDEFREF_TAG)
421421
end
422+
nothing
422423
end
423424

424425
# decide whether to send all data for a type (instead of just its name)
@@ -729,29 +730,32 @@ end
729730

730731

731732
function deserialize(s::AbstractSerializer, ::Type{TypeName})
733+
# the deserialize_cycle call can be delayed, since neither
734+
# Symbol nor Module will use the backref table
732735
number = read(s.io, UInt64)
733-
name = deserialize(s)
734-
mod = deserialize(s)
735-
if haskey(known_object_data, number)
736-
tn = known_object_data[number]::TypeName
737-
name = tn.name
738-
mod = tn.module
736+
name = deserialize(s)::Symbol
737+
mod = deserialize(s)::Module
738+
tn = get(known_object_data, number, nothing)
739+
if tn !== nothing
739740
makenew = false
740-
elseif isdefined(mod, name)
741+
elseif mod !== __deserialized_types__ && isdefined(mod, name)
741742
tn = getfield(mod, name).name
742743
# TODO: confirm somehow that the types match
743-
name = tn.name
744-
mod = tn.module
745744
makenew = false
745+
known_object_data[number] = tn
746746
else
747747
name = gensym()
748748
mod = __deserialized_types__
749749
tn = ccall(:jl_new_typename_in, Ref{TypeName}, (Any, Any), name, mod)
750750
makenew = true
751+
known_object_data[number] = tn
752+
end
753+
if !haskey(object_numbers, tn)
754+
# setup up reverse mapping for serialize
755+
object_numbers[tn] = number
751756
end
752757
deserialize_cycle(s, tn)
753758
deserialize_typename_body(s, tn, number, name, mod, makenew)
754-
makenew && (known_object_data[number] = tn)
755759
return tn
756760
end
757761

@@ -767,14 +771,18 @@ function deserialize_typename_body(s::AbstractSerializer, tn, number, name, mod,
767771

768772
if makenew
769773
tn.names = names
774+
# TODO: there's an unhanded cycle in the dependency graph at this point:
775+
# while deserializing super and/or types, we may have encountered
776+
# tn.primary and throw UndefRefException before we get to this point
770777
tn.primary = ccall(:jl_new_datatype, Any, (Any, Any, Any, Any, Any, Cint, Cint, Cint),
771778
tn, super, parameters, names, types,
772779
abstr, mutable, ninitialized)
773780
ty = tn.primary
774781
ccall(:jl_set_const, Void, (Any, Any, Any), mod, name, ty)
775-
if !isdefined(ty,:instance)
782+
if !isdefined(ty, :instance)
776783
if isempty(parameters) && !abstr && size == 0 && (!mutable || isempty(names))
777-
setfield!(ty, :instance, ccall(:jl_new_struct, Any, (Any,Any...), ty))
784+
# use setfield! directly to avoid `fieldtype` lowering expecting to see a Singleton object already on ty
785+
Core.setfield!(ty, :instance, ccall(:jl_new_struct, Any, (Any, Any...), ty))
778786
end
779787
end
780788
end

0 commit comments

Comments
 (0)