• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37997

29 Jan 2025 02:08AM UTC coverage: 17.283% (-68.7%) from 85.981%
#37997

push

local

web-flow
bpart: Start enforcing min_world for global variable definitions (#57150)

This is the analog of #57102 for global variables. Unlike for consants,
there is no automatic global backdate mechanism. The reasoning for this
is that global variables can be declared at any time, unlike constants
which can only be decalared once their value is available. As a result
code patterns using `Core.eval` to declare globals are rarer and likely
incorrect.

1 of 22 new or added lines in 3 files covered. (4.55%)

31430 existing lines in 188 files now uncovered.

7903 of 45728 relevant lines covered (17.28%)

98663.7 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

27.45
/stdlib/Serialization/src/Serialization.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
"""
4
Provide serialization of Julia objects via the functions
5
* [`serialize`](@ref)
6
* [`deserialize`](@ref)
7
"""
8
module Serialization
9

10
import Base: Bottom, unsafe_convert
11
import Core: svec, SimpleVector
12
using Base: unaliascopy, unwrap_unionall, require_one_based_indexing, ntupleany
13
using Core.IR
14

15
export serialize, deserialize, AbstractSerializer, Serializer
16

17
abstract type AbstractSerializer end
18

19
mutable struct Serializer{I<:IO} <: AbstractSerializer
20
    io::I
21
    counter::Int
22
    table::IdDict{Any,Any}
23
    pending_refs::Vector{Int}
24
    known_object_data::Dict{UInt64,Any}
25
    version::Int
UNCOV
26
    Serializer{I}(io::I) where I<:IO = new(io, 0, IdDict(), Int[], Dict{UInt64,Any}(), ser_version)
×
27
end
28

UNCOV
29
Serializer(io::IO) = Serializer{typeof(io)}(io)
×
30

31
## serializing values ##
32

33
const n_int_literals = 33
34
const n_reserved_slots = 24
35
const n_reserved_tags = 8
36

37
const TAGS = Any[
38
    Symbol, Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Int128, UInt128,
39
    Float16, Float32, Float64, Char, DataType, Union, UnionAll, Core.TypeName, Tuple,
40
    Array, Expr, LineNumberNode, :__LabelNode__, GotoNode, QuoteNode, CodeInfo, TypeVar,
41
    Core.Box, Core.MethodInstance, Module, Task, String, SimpleVector, Method,
42
    GlobalRef, SlotNumber, Const, NewvarNode, SSAValue,
43

44
    # dummy entries for tags that don't correspond directly to types
45
    Symbol, # UNDEFREF_TAG
46
    Symbol, # BACKREF_TAG
47
    Symbol, # LONGBACKREF_TAG
48
    Symbol, # SHORTBACKREF_TAG
49
    Symbol, # LONGTUPLE_TAG
50
    Symbol, # LONGSYMBOL_TAG
51
    Symbol, # LONGEXPR_TAG
52
    Symbol, # LONGSTRING_TAG
53
    Symbol, # SHORTINT64_TAG
54
    Symbol, # FULL_DATATYPE_TAG
55
    Symbol, # WRAPPER_DATATYPE_TAG
56
    Symbol, # OBJECT_TAG
57
    Symbol, # REF_OBJECT_TAG
58
    Symbol, # FULL_GLOBALREF_TAG
59
    Symbol, # HEADER_TAG
60
    Symbol, # IDDICT_TAG
61
    Symbol, # SHARED_REF_TAG
62
    ReturnNode, GotoIfNot,
63
    fill(Symbol, n_reserved_tags)...,
64

65
    (), Bool, Any, Bottom, Core.TypeofBottom, Type, svec(), Tuple{}, false, true, nothing,
66
    :Any, :Array, :TypeVar, :Box, :Tuple, :Ptr, :return, :call, Symbol("::"), :Function,
67
    :(=), :(==), :(===), :gotoifnot, :A, :B, :C, :M, :N, :T, :S, :X, :Y, :a, :b, :c, :d, :e, :f,
68
    :g, :h, :i, :j, :k, :l, :m, :n, :o, :p, :q, :r, :s, :t, :u, :v, :w, :x, :y, :z, :add_int,
69
    :sub_int, :mul_int, :add_float, :sub_float, :new, :mul_float, :bitcast, :start, :done, :next,
70
    :indexed_iterate, :getfield, :meta, :eq_int, :slt_int, :sle_int, :ne_int, :push_loc, :pop_loc,
71
    :pop, :arrayset, :arrayref, :apply_type, :inbounds, :getindex, :setindex!, :Core, :!, :+,
72
    :Base, :static_parameter, :convert, :colon, Symbol("#self#"), Symbol("#temp#"), :tuple, Symbol(""),
73

74
    fill(:_reserved_, n_reserved_slots)...,
75

76
    (Int32(0):Int32(n_int_literals-1))...,
77
    (Int64(0):Int64(n_int_literals-1))...
78
]
79

80
const NTAGS = length(TAGS)
81
@assert NTAGS == 255
82

83
const ser_version = 29 # do not make changes without bumping the version #!
84

85
format_version(::AbstractSerializer) = ser_version
×
UNCOV
86
format_version(s::Serializer) = s.version
×
87

88
function sertag(@nospecialize(v))
89
    # NOTE: we use jl_value_ptr directly since we know at least one of the arguments
90
    # in the comparison below is a singleton.
91
    ptr = ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), v)
200✔
92
    ptags = convert(Ptr{Ptr{Cvoid}}, pointer(TAGS))
200✔
93
    # note: constant ints & reserved slots never returned here
94
    @inbounds for i in 1:(NTAGS-(n_reserved_slots+2*n_int_literals))
7,122✔
95
        ptr == unsafe_load(ptags,i) && return i%Int32
26,078✔
96
    end
51,866✔
97
    return Int32(-1)
110✔
98
end
99
desertag(i::Int32) = @inbounds(TAGS[i])
184✔
100

101
# tags >= this just represent themselves, their whole representation is 1 byte
102
const VALUE_TAGS = sertag(())
103
const ZERO32_TAG = Int32(NTAGS-(2*n_int_literals-1))
104
const ZERO64_TAG = Int64(NTAGS-(n_int_literals-1))
105
const TRUE_TAG = sertag(true)
106
const FALSE_TAG = sertag(false)
107
const EMPTYTUPLE_TAG = sertag(())
108
const TUPLE_TAG = sertag(Tuple)
109
const SIMPLEVECTOR_TAG = sertag(SimpleVector)
110
const SYMBOL_TAG = sertag(Symbol)
111
const INT8_TAG = sertag(Int8)
112
const ARRAY_TAG = findfirst(==(Array), TAGS)%Int32
113
const EXPR_TAG = sertag(Expr)
114
const MODULE_TAG = sertag(Module)
115
const METHODINSTANCE_TAG = sertag(Core.MethodInstance)
116
const METHOD_TAG = sertag(Method)
117
const TASK_TAG = sertag(Task)
118
const DATATYPE_TAG = sertag(DataType)
119
const TYPENAME_TAG = sertag(Core.TypeName)
120
const INT32_TAG = sertag(Int32)
121
const INT64_TAG = sertag(Int64)
122
const GLOBALREF_TAG = sertag(GlobalRef)
123
const BOTTOM_TAG = sertag(Bottom)
124
const UNIONALL_TAG = sertag(UnionAll)
125
const STRING_TAG = sertag(String)
126
const o0 = sertag(SSAValue)
127
const UNDEFREF_TAG         = Int32(o0+1)
128
const BACKREF_TAG          = Int32(o0+2)
129
const LONGBACKREF_TAG      = Int32(o0+3)
130
const SHORTBACKREF_TAG     = Int32(o0+4)
131
const LONGTUPLE_TAG        = Int32(o0+5)
132
const LONGSYMBOL_TAG       = Int32(o0+6)
133
const LONGEXPR_TAG         = Int32(o0+7)
134
const LONGSTRING_TAG       = Int32(o0+8)
135
const SHORTINT64_TAG       = Int32(o0+9)
136
const FULL_DATATYPE_TAG    = Int32(o0+10)
137
const WRAPPER_DATATYPE_TAG = Int32(o0+11)
138
const OBJECT_TAG           = Int32(o0+12)
139
const REF_OBJECT_TAG       = Int32(o0+13)
140
const FULL_GLOBALREF_TAG   = Int32(o0+14)
141
const HEADER_TAG           = Int32(o0+15)
142
const IDDICT_TAG           = Int32(o0+16)
143
const SHARED_REF_TAG       = Int32(o0+17)
144

145
writetag(s::IO, tag) = (write(s, UInt8(tag)); nothing)
234✔
146

147
function write_as_tag(s::IO, tag)
148
    tag < VALUE_TAGS && write(s, UInt8(0))
100✔
149
    write(s, UInt8(tag))
100✔
150
    nothing
100✔
151
end
152

153
# cycle handling
154
function serialize_cycle(s::AbstractSerializer, @nospecialize(x))
74✔
155
    offs = get(s.table, x, -1)::Int
74✔
156
    if offs != -1
74✔
157
        if offs <= typemax(UInt16)
10✔
158
            writetag(s.io, SHORTBACKREF_TAG)
10✔
159
            write(s.io, UInt16(offs))
10✔
160
        elseif offs <= typemax(Int32)
×
161
            writetag(s.io, BACKREF_TAG)
×
162
            write(s.io, Int32(offs))
×
163
        else
164
            writetag(s.io, LONGBACKREF_TAG)
×
165
            write(s.io, Int64(offs))
×
166
        end
167
        return true
10✔
168
    end
169
    s.table[x] = s.counter
64✔
170
    s.counter += 1
64✔
171
    return false
64✔
172
end
173

UNCOV
174
function serialize_cycle_header(s::AbstractSerializer, @nospecialize(x))
×
UNCOV
175
    serialize_cycle(s, x) && return true
×
UNCOV
176
    serialize_type(s, typeof(x), true)
×
UNCOV
177
    return false
×
178
end
179

180
function reset_state(s::AbstractSerializer)
40✔
181
    s.counter = 0
40✔
182
    empty!(s.table)
40✔
183
    empty!(s.pending_refs)
40✔
184
    s
40✔
185
end
186

187
serialize(s::AbstractSerializer, x::Bool) = x ? writetag(s.io, TRUE_TAG) :
8✔
188
                                                writetag(s.io, FALSE_TAG)
189

UNCOV
190
serialize(s::AbstractSerializer, p::Ptr) = serialize_any(s, oftype(p, C_NULL))
×
191

192
serialize(s::AbstractSerializer, ::Tuple{}) = writetag(s.io, EMPTYTUPLE_TAG)
26✔
193

194
function serialize(s::AbstractSerializer, t::Tuple)
8✔
195
    l = length(t)
8✔
196
    if l <= NTAGS
8✔
197
        writetag(s.io, TUPLE_TAG)
8✔
198
        write(s.io, UInt8(l))
8✔
199
    else
UNCOV
200
        writetag(s.io, LONGTUPLE_TAG)
×
UNCOV
201
        write(s.io, Int32(l))
×
202
    end
203
    for x in t
8✔
204
        serialize(s, x)
16✔
205
    end
12✔
206
end
207

UNCOV
208
function serialize(s::AbstractSerializer, v::SimpleVector)
×
UNCOV
209
    writetag(s.io, SIMPLEVECTOR_TAG)
×
UNCOV
210
    write(s.io, Int32(length(v)))
×
UNCOV
211
    for x in v
×
UNCOV
212
        serialize(s, x)
×
UNCOV
213
    end
×
214
end
215

216
function serialize(s::AbstractSerializer, x::Symbol)
66✔
217
    tag = sertag(x)
10,718✔
218
    if tag > 0
66✔
219
        return write_as_tag(s.io, tag)
26✔
220
    end
221
    pname = unsafe_convert(Ptr{UInt8}, x)
40✔
222
    len = Int(ccall(:strlen, Csize_t, (Cstring,), pname))
40✔
223
    if len > 7
40✔
224
        serialize_cycle(s, x) && return
24✔
225
    end
226
    if len <= NTAGS
40✔
227
        writetag(s.io, SYMBOL_TAG)
40✔
228
        write(s.io, UInt8(len))
40✔
229
    else
UNCOV
230
        writetag(s.io, LONGSYMBOL_TAG)
×
UNCOV
231
        write(s.io, Int32(len))
×
232
    end
233
    unsafe_write(s.io, pname, len)
40✔
234
    nothing
40✔
235
end
236

237
function serialize_array_data(s::IO, a)
238
    require_one_based_indexing(a)
4✔
239
    isempty(a) && return 0
4✔
240
    if eltype(a) === Bool
4✔
UNCOV
241
        last = a[1]::Bool
×
UNCOV
242
        count = 1
×
UNCOV
243
        for i = 2:length(a)
×
UNCOV
244
            if a[i]::Bool != last || count == 127
×
UNCOV
245
                write(s, UInt8((UInt8(last) << 7) | count))
×
UNCOV
246
                last = a[i]::Bool
×
UNCOV
247
                count = 1
×
248
            else
UNCOV
249
                count += 1
×
250
            end
UNCOV
251
        end
×
UNCOV
252
        write(s, UInt8((UInt8(last) << 7) | count))
×
253
    else
254
        write(s, a)
4✔
255
    end
256
end
257

258
function serialize(s::AbstractSerializer, a::Array)
8✔
259
    serialize_cycle(s, a) && return
8✔
260
    elty = eltype(a)
8✔
261
    writetag(s.io, ARRAY_TAG)
8✔
262
    if elty !== UInt8
8✔
263
        serialize(s, elty)
8✔
264
    end
265
    if ndims(a) != 1
8✔
UNCOV
266
        serialize(s, size(a))
×
267
    else
268
        serialize(s, length(a))
8✔
269
    end
270
    if isbitstype(elty)
8✔
271
        serialize_array_data(s.io, a)
4✔
272
    else
273
        sizehint!(s.table, div(length(a),4))  # prepare for lots of pointers
4✔
274
        @inbounds for i in eachindex(a)
4✔
275
            if isassigned(a, i)
2✔
276
                serialize(s, a[i])
2✔
277
            else
UNCOV
278
                writetag(s.io, UNDEFREF_TAG)
×
279
            end
280
        end
2✔
281
    end
282
end
283

UNCOV
284
function serialize(s::AbstractSerializer, a::SubArray{T,N,A}) where {T,N,A<:Array}
×
285
    # SubArray's copy only selects the relevant data (and reduces the size) but does not
286
    # preserve the type of the argument. This internal function does both:
UNCOV
287
    b = unaliascopy(a)
×
UNCOV
288
    serialize_any(s, b)
×
289
end
290

291
serialize(s::AbstractSerializer, m::GenericMemory) = error("GenericMemory{:atomic} currently cannot be serialized")
×
UNCOV
292
function serialize(s::AbstractSerializer, m::Memory)
×
UNCOV
293
    serialize_cycle_header(s, m) && return
×
UNCOV
294
    serialize(s, length(m))
×
UNCOV
295
    elty = eltype(m)
×
UNCOV
296
    if isbitstype(elty)
×
UNCOV
297
        serialize_array_data(s.io, m)
×
298
    else
299
        sizehint!(s.table, div(length(m),4))  # prepare for lots of pointers
×
300
        @inbounds for i in eachindex(m)
×
301
            if isassigned(m, i)
×
302
                serialize(s, m[i])
×
303
            else
304
                writetag(s.io, UNDEFREF_TAG)
×
305
            end
306
        end
×
307
    end
308
end
309

310
function serialize(s::AbstractSerializer, x::GenericMemoryRef)
×
311
    serialize_type(s, typeof(x))
×
312
    serialize(s, getfield(x, :mem))
×
313
    serialize(s, Base.memoryrefoffset(x))
×
314
end
315

316
function serialize(s::AbstractSerializer, ss::String)
2✔
317
    len = sizeof(ss)
2✔
318
    if len > 7
2✔
319
        serialize_cycle(s, ss) && return
2✔
320
        writetag(s.io, SHARED_REF_TAG)
2✔
321
    end
322
    if len <= NTAGS
2✔
323
        writetag(s.io, STRING_TAG)
2✔
324
        write(s.io, UInt8(len))
2✔
325
    else
UNCOV
326
        writetag(s.io, LONGSTRING_TAG)
×
UNCOV
327
        write(s.io, Int64(len))
×
328
    end
329
    write(s.io, ss)
2✔
330
    nothing
2✔
331
end
332

UNCOV
333
function serialize(s::AbstractSerializer, ss::SubString{String})
×
334
    # avoid saving a copy of the parent string, keeping the type of ss
UNCOV
335
    serialize_any(s, SubString(String(ss)))
×
336
end
337

338
# Don't serialize the pointers
UNCOV
339
function serialize(s::AbstractSerializer, r::Regex)
×
UNCOV
340
    serialize_type(s, typeof(r))
×
UNCOV
341
    serialize(s, r.pattern)
×
UNCOV
342
    serialize(s, r.compile_options)
×
UNCOV
343
    serialize(s, r.match_options)
×
344
end
345

UNCOV
346
function serialize(s::AbstractSerializer, n::BigInt)
×
UNCOV
347
    serialize_type(s, BigInt)
×
UNCOV
348
    serialize(s, string(n, base = 62))
×
349
end
350

UNCOV
351
function serialize(s::AbstractSerializer, ex::Expr)
×
UNCOV
352
    serialize_cycle(s, ex) && return
×
UNCOV
353
    l = length(ex.args)
×
UNCOV
354
    if l <= NTAGS
×
UNCOV
355
        writetag(s.io, EXPR_TAG)
×
UNCOV
356
        write(s.io, UInt8(l))
×
357
    else
UNCOV
358
        writetag(s.io, LONGEXPR_TAG)
×
UNCOV
359
        write(s.io, Int32(l))
×
360
    end
UNCOV
361
    serialize(s, ex.head)
×
UNCOV
362
    for a in ex.args
×
UNCOV
363
        serialize(s, a)
×
UNCOV
364
    end
×
365
end
366

UNCOV
367
function serialize_dict_data(s::AbstractSerializer, d::AbstractDict)
×
UNCOV
368
    write(s.io, Int32(length(d)))
×
UNCOV
369
    for (k,v) in d
×
UNCOV
370
        serialize(s, k)
×
UNCOV
371
        serialize(s, v)
×
UNCOV
372
    end
×
373
end
374

UNCOV
375
function serialize(s::AbstractSerializer, d::Dict)
×
UNCOV
376
    serialize_cycle_header(s, d) && return
×
UNCOV
377
    serialize_dict_data(s, d)
×
378
end
379

UNCOV
380
function serialize(s::AbstractSerializer, d::IdDict)
×
UNCOV
381
    serialize_cycle(s, d) && return
×
UNCOV
382
    writetag(s.io, IDDICT_TAG)
×
UNCOV
383
    serialize_type_data(s, typeof(d))
×
UNCOV
384
    serialize_dict_data(s, d)
×
385
end
386

387
function serialize_mod_names(s::AbstractSerializer, m::Module)
32✔
388
    p = parentmodule(m)
32✔
389
    if p === m || m === Base
50✔
390
        key = Base.root_module_key(m)
30✔
391
        uuid = key.uuid
30✔
392
        serialize(s, uuid === nothing ? nothing : uuid.value)
34✔
393
        serialize(s, Symbol(key.name))
30✔
394
    else
395
        serialize_mod_names(s, p)
2✔
396
        serialize(s, nameof(m))
2✔
397
    end
398
end
399

400
function serialize(s::AbstractSerializer, m::Module)
30✔
401
    writetag(s.io, MODULE_TAG)
30✔
402
    serialize_mod_names(s, m)
30✔
403
    writetag(s.io, EMPTYTUPLE_TAG)
30✔
404
end
405

406
# TODO: make this bidirectional, so objects can be sent back via the same key
407
const object_numbers = WeakKeyDict()
408
const obj_number_salt = Ref{UInt64}(0)
UNCOV
409
function object_number(s::AbstractSerializer, @nospecialize(l))
×
UNCOV
410
    global obj_number_salt, object_numbers
×
UNCOV
411
    if haskey(object_numbers, l)
×
UNCOV
412
        return object_numbers[l]
×
413
    end
UNCOV
414
    ln = obj_number_salt[]
×
UNCOV
415
    object_numbers[l] = ln
×
UNCOV
416
    obj_number_salt[] += 1
×
UNCOV
417
    return ln::UInt64
×
418
end
419

420
lookup_object_number(s::AbstractSerializer, n::UInt64) = nothing
×
421

422
remember_object(s::AbstractSerializer, @nospecialize(o), n::UInt64) = nothing
×
423

UNCOV
424
function lookup_object_number(s::Serializer, n::UInt64)
×
UNCOV
425
    return get(s.known_object_data, n, nothing)
×
426
end
427

UNCOV
428
function remember_object(s::Serializer, @nospecialize(o), n::UInt64)
×
UNCOV
429
    s.known_object_data[n] = o
×
UNCOV
430
    return nothing
×
431
end
432

UNCOV
433
function serialize(s::AbstractSerializer, meth::Method)
×
UNCOV
434
    serialize_cycle(s, meth) && return
×
UNCOV
435
    writetag(s.io, METHOD_TAG)
×
UNCOV
436
    write(s.io, object_number(s, meth))
×
UNCOV
437
    serialize(s, meth.module)
×
UNCOV
438
    serialize(s, meth.name)
×
UNCOV
439
    serialize(s, meth.file)
×
UNCOV
440
    serialize(s, meth.line)
×
UNCOV
441
    serialize(s, meth.sig)
×
UNCOV
442
    serialize(s, meth.slot_syms)
×
UNCOV
443
    serialize(s, meth.nargs)
×
UNCOV
444
    serialize(s, meth.isva)
×
UNCOV
445
    serialize(s, meth.is_for_opaque_closure)
×
UNCOV
446
    serialize(s, meth.nospecializeinfer)
×
UNCOV
447
    serialize(s, meth.constprop)
×
UNCOV
448
    serialize(s, meth.purity)
×
UNCOV
449
    if isdefined(meth, :source)
×
UNCOV
450
        serialize(s, Base._uncompressed_ast(meth))
×
451
    else
452
        serialize(s, nothing)
×
453
    end
UNCOV
454
    if isdefined(meth, :generator)
×
455
        serialize(s, meth.generator)
×
456
    else
UNCOV
457
        serialize(s, nothing)
×
458
    end
UNCOV
459
    if isdefined(meth, :recursion_relation)
×
460
        serialize(s, method.recursion_relation)
×
461
    else
UNCOV
462
        serialize(s, nothing)
×
463
    end
UNCOV
464
    if isdefined(meth, :external_mt)
×
465
        error("cannot serialize Method objects with external method tables")
×
466
    end
UNCOV
467
    nothing
×
468
end
469

470
function serialize(s::AbstractSerializer, linfo::Core.MethodInstance)
×
471
    serialize_cycle(s, linfo) && return
×
472
    writetag(s.io, METHODINSTANCE_TAG)
×
473
    serialize(s, nothing)  # for backwards compat
×
474
    serialize(s, linfo.sparam_vals)
×
475
    serialize(s, Any)  # for backwards compat
×
476
    serialize(s, linfo.specTypes)
×
477
    serialize(s, linfo.def)
×
478
    nothing
×
479
end
480

UNCOV
481
function serialize(s::AbstractSerializer, t::Task)
×
UNCOV
482
    serialize_cycle(s, t) && return
×
UNCOV
483
    if istaskstarted(t) && !istaskdone(t)
×
484
        error("cannot serialize a running Task")
×
485
    end
UNCOV
486
    writetag(s.io, TASK_TAG)
×
UNCOV
487
    serialize(s, t.code)
×
UNCOV
488
    serialize(s, t.storage)
×
UNCOV
489
    serialize(s, t.state)
×
UNCOV
490
    if t._isexception && (stk = Base.current_exceptions(t); !isempty(stk))
×
491
        # the exception stack field is hidden inside the task, so if there
492
        # is any information there make a CapturedException from it instead.
493
        # TODO: Handle full exception chain, not just the first one.
UNCOV
494
        serialize(s, CapturedException(stk[1].exception, stk[1].backtrace))
×
495
    else
UNCOV
496
        serialize(s, t.result)
×
497
    end
UNCOV
498
    serialize(s, t._isexception)
×
499
end
500

UNCOV
501
function serialize(s::AbstractSerializer, g::GlobalRef)
×
UNCOV
502
    if (g.mod === __deserialized_types__ ) ||
×
503
        (g.mod === Main && isdefined(g.mod, g.name) && isconst(g.mod, g.name))
504

UNCOV
505
        v = getglobal(g.mod, g.name)
×
UNCOV
506
        unw = unwrap_unionall(v)
×
UNCOV
507
        if isa(unw,DataType) && v === unw.name.wrapper && should_send_whole_type(s, unw)
×
508
            # handle references to types in Main by sending the whole type.
509
            # needed to be able to send nested functions (#15451).
UNCOV
510
            writetag(s.io, FULL_GLOBALREF_TAG)
×
UNCOV
511
            serialize(s, v)
×
UNCOV
512
            return
×
513
        end
514
    end
UNCOV
515
    writetag(s.io, GLOBALREF_TAG)
×
UNCOV
516
    serialize(s, g.mod)
×
UNCOV
517
    serialize(s, g.name)
×
518
end
519

UNCOV
520
function serialize(s::AbstractSerializer, t::Core.TypeName)
×
UNCOV
521
    serialize_cycle(s, t) && return
×
UNCOV
522
    writetag(s.io, TYPENAME_TAG)
×
UNCOV
523
    write(s.io, object_number(s, t))
×
UNCOV
524
    serialize_typename(s, t)
×
525
end
526

UNCOV
527
function serialize_typename(s::AbstractSerializer, t::Core.TypeName)
×
UNCOV
528
    serialize(s, t.name)
×
UNCOV
529
    serialize(s, t.names)
×
UNCOV
530
    primary = unwrap_unionall(t.wrapper)
×
UNCOV
531
    serialize(s, primary.super)
×
UNCOV
532
    serialize(s, primary.parameters)
×
UNCOV
533
    serialize(s, primary.types)
×
UNCOV
534
    serialize(s, Base.issingletontype(primary))
×
UNCOV
535
    serialize(s, t.flags & 0x1 == 0x1) # .abstract
×
UNCOV
536
    serialize(s, t.flags & 0x2 == 0x2) # .mutable
×
UNCOV
537
    serialize(s, Int32(length(primary.types) - t.n_uninitialized))
×
UNCOV
538
    serialize(s, t.max_methods)
×
UNCOV
539
    if isdefined(t, :mt) && t.mt !== Symbol.name.mt
×
UNCOV
540
        serialize(s, t.mt.name)
×
UNCOV
541
        serialize(s, collect(Base.MethodList(t.mt)))
×
UNCOV
542
        serialize(s, t.mt.max_args)
×
UNCOV
543
        kws = collect(methods(Core.kwcall, (Any, t.wrapper, Vararg)))
×
UNCOV
544
        if isempty(kws)
×
UNCOV
545
            writetag(s.io, UNDEFREF_TAG)
×
546
        else
UNCOV
547
            serialize(s, kws)
×
548
        end
549
    else
UNCOV
550
        writetag(s.io, UNDEFREF_TAG)
×
551
    end
UNCOV
552
    nothing
×
553
end
554

555
# decide whether to send all data for a type (instead of just its name)
556
function should_send_whole_type(s, t::DataType)
557
    tn = t.name
40✔
558
    if isdefined(tn, :mt)
40✔
559
        # TODO improve somehow
560
        # send whole type for anonymous functions in Main
561
        name = tn.mt.name
40✔
562
        mod = tn.module
40✔
563
        isanonfunction = mod === Main && # only Main
40✔
564
            t.super === Function && # only Functions
565
            unsafe_load(unsafe_convert(Ptr{UInt8}, tn.name)) == UInt8('#') && # hidden type
566
            (!isdefined(mod, name) || t != typeof(getglobal(mod, name))) # XXX: 95% accurate test for this being an inner function
567
            # TODO: more accurate test? (tn.name !== "#" name)
568
        #TODO: iskw = startswith(tn.name, "#kw#") && ???
569
        #TODO: iskw && return send-as-kwftype
570
        return mod === __deserialized_types__ || isanonfunction
80✔
571
    end
UNCOV
572
    return false
×
573
end
574

575
function serialize_type_data(s, @nospecialize(t::DataType))
40✔
576
    whole = should_send_whole_type(s, t)
80✔
577
    iswrapper = (t === unwrap_unionall(t.name.wrapper))
40✔
578
    if whole && iswrapper
40✔
UNCOV
579
        writetag(s.io, WRAPPER_DATATYPE_TAG)
×
UNCOV
580
        serialize(s, t.name)
×
UNCOV
581
        return
×
582
    end
583
    serialize_cycle(s, t) && return
40✔
584
    if whole
30✔
UNCOV
585
        writetag(s.io, FULL_DATATYPE_TAG)
×
UNCOV
586
        serialize(s, t.name)
×
587
    else
588
        writetag(s.io, DATATYPE_TAG)
30✔
589
        serialize(s, nameof(t))
30✔
590
        serialize(s, parentmodule(t))
30✔
591
    end
592
    if !isempty(t.parameters)
30✔
593
        if iswrapper
20✔
UNCOV
594
            write(s.io, Int32(0))
×
595
        else
596
            write(s.io, Int32(length(t.parameters)))
20✔
597
            for p in t.parameters
40✔
598
                serialize(s, p)
60✔
599
            end
60✔
600
        end
601
    end
602
    nothing
30✔
603
end
604

605
function serialize(s::AbstractSerializer, t::DataType)
48✔
606
    tag = sertag(t)
3,482✔
607
    tag > 0 && return write_as_tag(s.io, tag)
48✔
608
    if t === Tuple
10✔
609
        # `sertag` is not able to find types === to `Tuple` because they
610
        # will not have been hash-consed. Plus `serialize_type_data` does not
611
        # handle this case correctly, since Tuple{} != Tuple. `Tuple` is the
612
        # only type with this property. issue #15849
613
        return write_as_tag(s.io, TUPLE_TAG)
×
614
    end
615
    serialize_type_data(s, t)
10✔
616
end
617

618
function serialize_type(s::AbstractSerializer, @nospecialize(t::DataType), ref::Bool = false)
30✔
619
    tag = sertag(t)
4,980✔
620
    tag > 0 && return writetag(s.io, tag)
30✔
621
    writetag(s.io, ref ? REF_OBJECT_TAG : OBJECT_TAG)
30✔
622
    serialize_type_data(s, t)
30✔
623
end
624

625
function serialize(s::AbstractSerializer, n::Int32)
UNCOV
626
    if 0 <= n <= (n_int_literals-1)
×
UNCOV
627
        write(s.io, UInt8(ZERO32_TAG+n))
×
628
    else
UNCOV
629
        writetag(s.io, INT32_TAG)
×
UNCOV
630
        write(s.io, n)
×
631
    end
UNCOV
632
    nothing
×
633
end
634

635
function serialize(s::AbstractSerializer, n::Int64)
26✔
636
    if 0 <= n <= (n_int_literals-1)
26✔
637
        write(s.io, UInt8(ZERO64_TAG+n))
20✔
638
    elseif typemin(Int32) <= n <= typemax(Int32)
6✔
639
        writetag(s.io, SHORTINT64_TAG)
6✔
640
        write(s.io, Int32(n))
6✔
641
    else
UNCOV
642
        writetag(s.io, INT64_TAG)
×
UNCOV
643
        write(s.io, n)
×
644
    end
645
    nothing
26✔
646
end
647

648
for i in 0:13
649
    tag = Int32(INT8_TAG + i)
650
    ty = TAGS[tag]
651
    (ty === Int32 || ty === Int64) && continue
652
    @eval serialize(s::AbstractSerializer, n::$ty) = (writetag(s.io, $tag); write(s.io, n); nothing)
4✔
653
end
654

655
serialize(s::AbstractSerializer, ::Type{Bottom}) = write_as_tag(s.io, BOTTOM_TAG)
10✔
656

UNCOV
657
function serialize(s::AbstractSerializer, u::UnionAll)
×
UNCOV
658
    writetag(s.io, UNIONALL_TAG)
×
UNCOV
659
    n = 0; t = u
×
UNCOV
660
    while isa(t, UnionAll)
×
UNCOV
661
        t = t.body
×
UNCOV
662
        n += 1
×
UNCOV
663
    end
×
UNCOV
664
    if isa(t, DataType) && t === unwrap_unionall(t.name.wrapper)
×
UNCOV
665
        write(s.io, UInt8(1))
×
UNCOV
666
        write(s.io, Int16(n))
×
UNCOV
667
        serialize(s, t)
×
668
    else
UNCOV
669
        write(s.io, UInt8(0))
×
UNCOV
670
        serialize(s, u.var)
×
UNCOV
671
        serialize(s, u.body)
×
672
    end
673
end
674

675
serialize(s::AbstractSerializer, @nospecialize(x)) = serialize_any(s, x)
56✔
676

UNCOV
677
function serialize(s::AbstractSerializer, x::Core.AddrSpace)
×
UNCOV
678
    serialize_type(s, typeof(x))
×
UNCOV
679
    write(s.io, Core.bitcast(UInt8, x))
×
680
end
681

682
function serialize_any(s::AbstractSerializer, @nospecialize(x))
56✔
683
    tag = sertag(x)
7,008✔
684
    if tag > 0
56✔
685
        return write_as_tag(s.io, tag)
26✔
686
    end
687
    t = typeof(x)::DataType
30✔
688
    if isprimitivetype(t)
30✔
UNCOV
689
        serialize_type(s, t)
×
UNCOV
690
        write(s.io, x)
×
691
    else
692
        if ismutable(x)
30✔
UNCOV
693
            serialize_cycle(s, x) && return
×
UNCOV
694
            serialize_type(s, t, true)
×
695
        else
696
            serialize_type(s, t, false)
30✔
697
        end
698
        nf = nfields(x)
30✔
699
        for i in 1:nf
30✔
700
            if isdefined(x, i)
20✔
701
                serialize(s, getfield(x, i))
20✔
702
            else
UNCOV
703
                writetag(s.io, UNDEFREF_TAG)
×
704
            end
705
        end
20✔
706
    end
707
    nothing
30✔
708
end
709

710
"""
711
    Serialization.writeheader(s::AbstractSerializer)
712

713
Write an identifying header to the specified serializer. The header consists of
714
8 bytes as follows:
715

716
| Offset | Description                                     |
717
|:-------|:------------------------------------------------|
718
|   0    | tag byte (0x37)                                 |
719
|   1-2  | signature bytes "JL"                            |
720
|   3    | protocol version                                |
721
|   4    | bits 0-1: endianness: 0 = little, 1 = big       |
722
|   4    | bits 2-3: platform: 0 = 32-bit, 1 = 64-bit      |
723
|   5-7  | reserved                                        |
724
"""
UNCOV
725
function writeheader(s::AbstractSerializer)
×
UNCOV
726
    io = s.io
×
UNCOV
727
    writetag(io, HEADER_TAG)
×
UNCOV
728
    write(io, "JL")  # magic bytes
×
UNCOV
729
    write(io, UInt8(ser_version))
×
UNCOV
730
    endianness = (ENDIAN_BOM == 0x04030201 ? 0 :
×
731
                  ENDIAN_BOM == 0x01020304 ? 1 :
732
                  error("unsupported endianness in serializer"))
UNCOV
733
    machine = (sizeof(Int) == 4 ? 0 :
×
734
               sizeof(Int) == 8 ? 1 :
735
               error("unsupported word size in serializer"))
UNCOV
736
    write(io, UInt8(endianness) | (UInt8(machine) << 2))
×
UNCOV
737
    write(io, [0x00,0x00,0x00]) # 3 reserved bytes
×
UNCOV
738
    nothing
×
739
end
740

UNCOV
741
function readheader(s::AbstractSerializer)
×
742
    # Tag already read
UNCOV
743
    io = s.io
×
UNCOV
744
    m1 = read(io, UInt8)
×
UNCOV
745
    m2 = read(io, UInt8)
×
UNCOV
746
    if m1 != UInt8('J') || m2 != UInt8('L')
×
747
        error("Unsupported serialization format (got header magic bytes $m1 $m2)")
×
748
    end
UNCOV
749
    version    = read(io, UInt8)
×
UNCOV
750
    flags      = read(io, UInt8)
×
UNCOV
751
    reserved1  = read(io, UInt8)
×
UNCOV
752
    reserved2  = read(io, UInt8)
×
UNCOV
753
    reserved3  = read(io, UInt8)
×
UNCOV
754
    endianflag = flags & 0x3
×
UNCOV
755
    wordflag   = (flags >> 2) & 0x3
×
UNCOV
756
    wordsize = wordflag == 0 ? 4 :
×
757
               wordflag == 1 ? 8 :
758
               error("Unknown word size flag in header")
UNCOV
759
    endian_bom = endianflag == 0 ? 0x04030201 :
×
760
                 endianflag == 1 ? 0x01020304 :
761
                 error("Unknown endianness flag in header")
762
    # Check protocol compatibility.
UNCOV
763
    endian_bom == ENDIAN_BOM  || error("Serialized byte order mismatch ($(repr(endian_bom)))")
×
764
    # We don't check wordsize == sizeof(Int) here, as Int is encoded concretely
765
    # as Int32 or Int64, which should be enough to correctly deserialize a range
766
    # of data structures between Julia versions.
UNCOV
767
    if version > ser_version
×
UNCOV
768
        error("""Cannot read stream serialized with a newer version of Julia.
×
769
                 Got data version $version > current version $ser_version""")
770
    end
UNCOV
771
    s.version = version
×
UNCOV
772
    return
×
773
end
774

775
"""
776
    serialize(stream::IO, value)
777

778
Write an arbitrary value to a stream in an opaque format, such that it can be read back by
779
[`deserialize`](@ref). The read-back value will be as identical as possible to the original,
780
but note that `Ptr` values are serialized as all-zero bit patterns (`NULL`).
781

782
An 8-byte identifying header is written to the stream first. To avoid writing the header,
783
construct a `Serializer` and use it as the first argument to `serialize` instead.
784
See also [`Serialization.writeheader`](@ref).
785

786
The data format can change in minor (1.x) Julia releases, but files written by prior 1.x
787
versions will remain readable. The main exception to this is when the definition of a
788
type in an external package changes. If that occurs, it may be necessary to specify
789
an explicit compatible version of the affected package in your environment.
790
Renaming functions, even private functions, inside packages can also put existing files
791
out of sync. Anonymous functions require special care: because their names are automatically
792
generated, minor code changes can cause them to be renamed.
793
Serializing anonymous functions should be avoided in files intended for long-term storage.
794

795
In some cases, the word size (32- or 64-bit) of the reading and writing machines must match.
796
In rarer cases the OS or architecture must also match, for example when using packages
797
that contain platform-dependent code.
798
"""
UNCOV
799
function serialize(s::IO, x)
×
UNCOV
800
    ss = Serializer(s)
×
UNCOV
801
    writeheader(ss)
×
UNCOV
802
    serialize(ss, x)
×
803
end
804

805
"""
806
    serialize(filename::AbstractString, value)
807

808
Open a file and serialize the given value to it.
809

810
!!! compat "Julia 1.1"
811
    This method is available as of Julia 1.1.
812
"""
UNCOV
813
serialize(filename::AbstractString, x) = open(io->serialize(io, x), filename, "w")
×
814

815
## deserializing values ##
816

817
"""
818
    deserialize(stream)
819

820
Read a value written by [`serialize`](@ref). `deserialize` assumes the binary data read from
821
`stream` is correct and has been serialized by a compatible implementation of [`serialize`](@ref).
822
`deserialize` is designed for simplicity and performance, and so does not validate
823
the data read. Malformed data can result in process termination. The caller must ensure
824
the integrity and correctness of data read from `stream`.
825
"""
UNCOV
826
deserialize(s::IO) = deserialize(Serializer(s))
×
827

828
"""
829
    deserialize(filename::AbstractString)
830

831
Open a file and deserialize its contents.
832

833
!!! compat "Julia 1.1"
834
    This method is available as of Julia 1.1.
835
"""
UNCOV
836
deserialize(filename::AbstractString) = open(deserialize, filename)
×
837

838
function deserialize(s::AbstractSerializer)
272✔
839
    handle_deserialize(s, Int32(read(s.io, UInt8)::UInt8))
292✔
840
end
841

UNCOV
842
function deserialize_cycle(s::AbstractSerializer, @nospecialize(x))
×
UNCOV
843
    slot = pop!(s.pending_refs)
×
UNCOV
844
    s.table[slot] = x
×
UNCOV
845
    nothing
×
846
end
847

848
# optimized version of:
849
#     slot = s.counter; s.counter += 1
850
#     push!(s.pending_refs, slot)
851
#     slot = pop!(s.pending_refs)
852
#     s.table[slot] = x
853
function resolve_ref_immediately(s::AbstractSerializer, @nospecialize(x))
854
    s.table[s.counter] = x
24✔
855
    s.counter += 1
24✔
856
    nothing
24✔
857
end
858

859
function gettable(s::AbstractSerializer, id::Int)
860
    get(s.table, id) do
10✔
861
        errmsg = """Inconsistent Serializer state when deserializing.
×
862
            Attempt to access internal table with key $id failed.
863

864
            This might occur if the Serializer contexts when serializing and deserializing are inconsistent.
865
            In particular, if multiple serialize calls use the same Serializer object then
866
            the corresponding deserialize calls should also use the same Serializer object.
867
        """
868
        error(errmsg)
×
869
    end
870
end
871

872
# deserialize_ is an internal function to dispatch on the tag
873
# describing the serialized representation. the number of
874
# representations is fixed, so deserialize_ does not get extended.
875
function handle_deserialize(s::AbstractSerializer, b::Int32)
354✔
876
    if b == 0
354✔
877
        return desertag(Int32(read(s.io, UInt8)::UInt8))
14✔
878
    end
879
    if b >= VALUE_TAGS
340✔
880
        return desertag(b)
170✔
881
    elseif b == TUPLE_TAG
170✔
882
        return deserialize_tuple(s, Int(read(s.io, UInt8)::UInt8))
8✔
883
    elseif b == SHORTBACKREF_TAG
162✔
884
        id = read(s.io, UInt16)::UInt16
10✔
885
        return gettable(s, Int(id))
10✔
886
    elseif b == BACKREF_TAG
152✔
887
        id = read(s.io, Int32)::Int32
×
888
        return gettable(s, Int(id))
×
889
    elseif b == ARRAY_TAG
152✔
890
        return deserialize_array(s)
8✔
891
    elseif b == DATATYPE_TAG
144✔
892
        return deserialize_datatype(s, false)
30✔
893
    elseif b == FULL_DATATYPE_TAG
114✔
UNCOV
894
        return deserialize_datatype(s, true)
×
895
    elseif b == WRAPPER_DATATYPE_TAG
114✔
UNCOV
896
        tname = deserialize(s)::Core.TypeName
×
UNCOV
897
        return unwrap_unionall(tname.wrapper)
×
898
    elseif b == OBJECT_TAG
114✔
899
        t = deserialize(s)
30✔
900
        if t === Missing
30✔
901
            return missing
×
902
        end
903
        return deserialize(s, t)
30✔
904
    elseif b == REF_OBJECT_TAG
84✔
UNCOV
905
        slot = s.counter; s.counter += 1
×
UNCOV
906
        push!(s.pending_refs, slot)
×
UNCOV
907
        t = deserialize(s)
×
UNCOV
908
        return deserialize(s, t)
×
909
    elseif b == SHARED_REF_TAG
84✔
910
        slot = s.counter; s.counter += 1
2✔
911
        obj = deserialize(s)
2✔
912
        s.table[slot] = obj
2✔
913
        return obj
2✔
914
    elseif b == SYMBOL_TAG
82✔
915
        return deserialize_symbol(s, Int(read(s.io, UInt8)::UInt8))
40✔
916
    elseif b == SHORTINT64_TAG
42✔
917
        return Int64(read(s.io, Int32)::Int32)
6✔
918
    elseif b == EXPR_TAG
36✔
UNCOV
919
        return deserialize_expr(s, Int(read(s.io, UInt8)::UInt8))
×
920
    elseif b == MODULE_TAG
36✔
921
        return deserialize_module(s)
30✔
922
    elseif b == STRING_TAG
6✔
923
        return deserialize_string(s, Int(read(s.io, UInt8)::UInt8))
2✔
924
    elseif b == LONGSTRING_TAG
4✔
UNCOV
925
        return deserialize_string(s, Int(read(s.io, Int64)::Int64))
×
926
    elseif b == SIMPLEVECTOR_TAG
4✔
UNCOV
927
        return deserialize_svec(s)
×
928
    elseif b == GLOBALREF_TAG
4✔
UNCOV
929
        return GlobalRef(deserialize(s)::Module, deserialize(s)::Symbol)
×
930
    elseif b == FULL_GLOBALREF_TAG
4✔
UNCOV
931
        ty = deserialize(s)
×
UNCOV
932
        tn = unwrap_unionall(ty).name
×
UNCOV
933
        return GlobalRef(tn.module, tn.name)
×
934
    elseif b == LONGTUPLE_TAG
4✔
UNCOV
935
        return deserialize_tuple(s, Int(read(s.io, Int32)::Int32))
×
936
    elseif b == LONGEXPR_TAG
4✔
UNCOV
937
        return deserialize_expr(s, Int(read(s.io, Int32)::Int32))
×
938
    elseif b == LONGBACKREF_TAG
4✔
939
        id = read(s.io, Int64)::Int64
×
940
        return gettable(s, Int(id))
×
941
    elseif b == LONGSYMBOL_TAG
4✔
UNCOV
942
        return deserialize_symbol(s, Int(read(s.io, Int32)::Int32))
×
943
    elseif b == HEADER_TAG
4✔
UNCOV
944
        readheader(s)
×
UNCOV
945
        return deserialize(s)
×
946
    elseif b == INT8_TAG
4✔
UNCOV
947
        return read(s.io, Int8)
×
948
    elseif b == INT8_TAG+1
4✔
UNCOV
949
        return read(s.io, UInt8)
×
950
    elseif b == INT8_TAG+2
4✔
UNCOV
951
        return read(s.io, Int16)
×
952
    elseif b == INT8_TAG+3
4✔
UNCOV
953
        return read(s.io, UInt16)
×
954
    elseif b == INT32_TAG
4✔
UNCOV
955
        return read(s.io, Int32)
×
956
    elseif b == INT8_TAG+5
4✔
UNCOV
957
        return read(s.io, UInt32)
×
958
    elseif b == INT64_TAG
4✔
959
        return read(s.io, Int64)
×
960
    elseif b == INT8_TAG+7
4✔
UNCOV
961
        return read(s.io, UInt64)
×
962
    elseif b == INT8_TAG+8
4✔
UNCOV
963
        return read(s.io, Int128)
×
964
    elseif b == INT8_TAG+9
4✔
965
        return read(s.io, UInt128)
4✔
UNCOV
966
    elseif b == INT8_TAG+10
×
UNCOV
967
        return read(s.io, Float16)
×
UNCOV
968
    elseif b == INT8_TAG+11
×
969
        return read(s.io, Float32)
×
UNCOV
970
    elseif b == INT8_TAG+12
×
971
        return read(s.io, Float64)
×
UNCOV
972
    elseif b == INT8_TAG+13
×
UNCOV
973
        return read(s.io, Char)
×
UNCOV
974
    elseif b == IDDICT_TAG
×
UNCOV
975
        slot = s.counter; s.counter += 1
×
UNCOV
976
        push!(s.pending_refs, slot)
×
UNCOV
977
        t = deserialize(s)
×
UNCOV
978
        return deserialize_dict(s, t)
×
979
    end
UNCOV
980
    t = desertag(b)::DataType
×
UNCOV
981
    if ismutabletype(t) && length(t.types) > 0  # manual specialization of fieldcount
×
UNCOV
982
        slot = s.counter; s.counter += 1
×
UNCOV
983
        push!(s.pending_refs, slot)
×
984
    end
UNCOV
985
    return deserialize(s, t)
×
986
end
987

988
function deserialize_symbol(s::AbstractSerializer, len::Int)
40✔
989
    str = Base._string_n(len)
40✔
990
    unsafe_read(s.io, pointer(str), len)
40✔
991
    sym = Symbol(str)
40✔
992
    if len > 7
40✔
993
        resolve_ref_immediately(s, sym)
24✔
994
    end
995
    return sym
40✔
996
end
997

998
deserialize_tuple(s::AbstractSerializer, len) = ntupleany(i->deserialize(s), len)
20✔
999

UNCOV
1000
function deserialize_svec(s::AbstractSerializer)
×
UNCOV
1001
    n = read(s.io, Int32)
×
UNCOV
1002
    svec(Any[ deserialize(s) for i=1:n ]...)
×
1003
end
1004

1005
function deserialize_module(s::AbstractSerializer)
30✔
1006
    mkey = deserialize(s)
30✔
1007
    if isa(mkey, Tuple)
30✔
1008
        # old version, TODO: remove
1009
        if mkey === ()
×
1010
            return Main
×
1011
        end
1012
        m = Base.root_module(mkey[1])
×
1013
        for i = 2:length(mkey)
×
1014
            m = getglobal(m, mkey[i])::Module
×
1015
        end
×
1016
    else
1017
        name = String(deserialize(s)::Symbol)
30✔
1018
        pkg = (mkey === nothing) ? Base.PkgId(name) : Base.PkgId(Base.UUID(mkey), name)
34✔
1019
        m = Base.root_module(pkg)
30✔
1020
        mname = deserialize(s)
30✔
1021
        while mname !== ()
32✔
1022
            m = getglobal(m, mname)::Module
2✔
1023
            mname = deserialize(s)
2✔
1024
        end
2✔
1025
    end
1026
    return m
30✔
1027
end
1028

UNCOV
1029
function deserialize(s::AbstractSerializer, ::Type{Method})
×
UNCOV
1030
    lnumber = read(s.io, UInt64)
×
UNCOV
1031
    meth = lookup_object_number(s, lnumber)
×
UNCOV
1032
    if meth !== nothing
×
UNCOV
1033
        meth = meth::Method
×
UNCOV
1034
        makenew = false
×
1035
    else
UNCOV
1036
        meth = ccall(:jl_new_method_uninit, Ref{Method}, (Any,), Main)
×
UNCOV
1037
        makenew = true
×
1038
    end
UNCOV
1039
    deserialize_cycle(s, meth)
×
UNCOV
1040
    mod = deserialize(s)::Module
×
UNCOV
1041
    name = deserialize(s)::Symbol
×
UNCOV
1042
    file = deserialize(s)::Symbol
×
UNCOV
1043
    line = deserialize(s)::Int32
×
UNCOV
1044
    sig = deserialize(s)::Type
×
UNCOV
1045
    syms = deserialize(s)
×
UNCOV
1046
    if syms isa SimpleVector
×
1047
        # < v1.2
UNCOV
1048
        _ambig = deserialize(s)
×
1049
    else
UNCOV
1050
        slot_syms = syms::String
×
1051
    end
UNCOV
1052
    nargs = deserialize(s)::Int32
×
UNCOV
1053
    isva = deserialize(s)::Bool
×
UNCOV
1054
    is_for_opaque_closure = false
×
UNCOV
1055
    nospecializeinfer = false
×
UNCOV
1056
    constprop = 0x00
×
UNCOV
1057
    purity = 0x0000
×
UNCOV
1058
    template_or_is_opaque = deserialize(s)
×
UNCOV
1059
    if isa(template_or_is_opaque, Bool)
×
UNCOV
1060
        is_for_opaque_closure = template_or_is_opaque
×
UNCOV
1061
        if format_version(s) >= 24
×
UNCOV
1062
            nospecializeinfer = deserialize(s)::Bool
×
1063
        end
UNCOV
1064
        if format_version(s) >= 14
×
UNCOV
1065
            constprop = deserialize(s)::UInt8
×
1066
        end
UNCOV
1067
        if format_version(s) >= 26
×
UNCOV
1068
            purity = deserialize(s)::UInt16
×
1069
        elseif format_version(s) >= 17
×
1070
            purity = UInt16(deserialize(s)::UInt8)
×
1071
        end
UNCOV
1072
        template = deserialize(s)
×
1073
    else
UNCOV
1074
        template = template_or_is_opaque
×
1075
    end
UNCOV
1076
    generator = deserialize(s)
×
UNCOV
1077
    recursion_relation = nothing
×
UNCOV
1078
    if format_version(s) >= 15
×
UNCOV
1079
        recursion_relation = deserialize(s)
×
1080
    end
UNCOV
1081
    if makenew
×
UNCOV
1082
        meth.module = mod
×
UNCOV
1083
        meth.debuginfo = NullDebugInfo
×
UNCOV
1084
        meth.name = name
×
UNCOV
1085
        meth.file = file
×
UNCOV
1086
        meth.line = line
×
UNCOV
1087
        meth.sig = sig
×
UNCOV
1088
        meth.nargs = nargs
×
UNCOV
1089
        meth.isva = isva
×
UNCOV
1090
        meth.is_for_opaque_closure = is_for_opaque_closure
×
UNCOV
1091
        meth.nospecializeinfer = nospecializeinfer
×
UNCOV
1092
        meth.constprop = constprop
×
UNCOV
1093
        meth.purity = purity
×
UNCOV
1094
        if template !== nothing
×
1095
            # TODO: compress template
UNCOV
1096
            template = template::CodeInfo
×
UNCOV
1097
            if format_version(s) < 29
×
UNCOV
1098
                template.nargs = nargs
×
UNCOV
1099
                template.isva = isva
×
1100
            end
UNCOV
1101
            meth.source = template
×
UNCOV
1102
            meth.debuginfo = template.debuginfo
×
UNCOV
1103
            if !@isdefined(slot_syms)
×
UNCOV
1104
                slot_syms = ccall(:jl_compress_argnames, Ref{String}, (Any,), meth.source.slotnames)
×
1105
            end
1106
        end
UNCOV
1107
        meth.slot_syms = slot_syms
×
UNCOV
1108
        if generator !== nothing
×
1109
            meth.generator = generator
×
1110
        end
UNCOV
1111
        if recursion_relation !== nothing
×
1112
            meth.recursion_relation = recursion_relation
×
1113
        end
UNCOV
1114
        if !is_for_opaque_closure
×
UNCOV
1115
            mt = ccall(:jl_method_table_for, Any, (Any,), sig)
×
UNCOV
1116
            if mt !== nothing && nothing === ccall(:jl_methtable_lookup, Any, (Any, Any, UInt), mt, sig, Base.get_world_counter())
×
UNCOV
1117
                ccall(:jl_method_table_insert, Cvoid, (Any, Any, Ptr{Cvoid}), mt, meth, C_NULL)
×
1118
            end
1119
        end
UNCOV
1120
        remember_object(s, meth, lnumber)
×
1121
    end
UNCOV
1122
    return meth
×
1123
end
1124

1125
function deserialize(s::AbstractSerializer, ::Type{Core.MethodInstance})
×
1126
    linfo = ccall(:jl_new_method_instance_uninit, Ref{Core.MethodInstance}, (Ptr{Cvoid},), C_NULL)
×
1127
    deserialize_cycle(s, linfo)
×
1128
    if format_version(s) < 28
×
1129
        tag = Int32(read(s.io, UInt8)::UInt8)
×
1130
        if tag != UNDEFREF_TAG
×
1131
            code = handle_deserialize(s, tag)::CodeInfo
×
1132
            ci = ccall(:jl_new_codeinst_for_uninferred, Ref{CodeInstance}, (Any, Any), linfo, code)
×
1133
            @atomic linfo.cache = ci
×
1134
        end
1135
    end
1136
    tag = Int32(read(s.io, UInt8)::UInt8)
×
1137
    if tag != UNDEFREF_TAG
×
1138
        # for reading files prior to v1.2
1139
        handle_deserialize(s, tag)
×
1140
    end
1141
    linfo.sparam_vals = deserialize(s)::SimpleVector
×
1142
    _rettype = deserialize(s)  # for backwards compat
×
1143
    linfo.specTypes = deserialize(s)
×
1144
    linfo.def = deserialize(s)
×
1145
    return linfo
×
1146
end
1147

UNCOV
1148
function deserialize(s::AbstractSerializer, ::Type{Core.LineInfoNode})
×
UNCOV
1149
    mod = deserialize(s)
×
UNCOV
1150
    if mod isa Module
×
UNCOV
1151
        method = deserialize(s)
×
1152
    else
1153
        # files post v1.2 and pre v1.6 are broken
1154
        method = mod
×
1155
        mod = Main
×
1156
    end
UNCOV
1157
    return Core.LineInfoNode(mod, method, deserialize(s)::Symbol, Int32(deserialize(s)::Union{Int32, Int}), Int32(deserialize(s)::Union{Int32, Int}))
×
1158
end
1159

1160

1161
function deserialize(s::AbstractSerializer, ::Type{PhiNode})
×
1162
    edges = deserialize(s)
×
1163
    if edges isa Vector{Any}
×
1164
        edges = Vector{Int32}(edges)
×
1165
    end
1166
    values = deserialize(s)::Vector{Any}
×
1167
    return PhiNode(edges, values)
×
1168
end
1169

UNCOV
1170
function deserialize(s::AbstractSerializer, ::Type{CodeInfo})
×
UNCOV
1171
    ci = ccall(:jl_new_code_info_uninit, Ref{CodeInfo}, ())
×
UNCOV
1172
    deserialize_cycle(s, ci)
×
UNCOV
1173
    code = deserialize(s)::Vector{Any}
×
UNCOV
1174
    ci.code = code
×
UNCOV
1175
    ci.debuginfo = NullDebugInfo
×
1176
    # allow older-style IR with return and gotoifnot Exprs
UNCOV
1177
    for i in 1:length(code)
×
UNCOV
1178
        stmt = code[i]
×
UNCOV
1179
        if isa(stmt, Expr)
×
UNCOV
1180
            ex = stmt::Expr
×
UNCOV
1181
            if ex.head === :return
×
UNCOV
1182
                code[i] = ReturnNode(isempty(ex.args) ? nothing : ex.args[1])
×
UNCOV
1183
            elseif ex.head === :gotoifnot
×
1184
                code[i] = GotoIfNot(ex.args[1], ex.args[2])
×
1185
            end
1186
        end
UNCOV
1187
    end
×
UNCOV
1188
    _x = deserialize(s)
×
UNCOV
1189
    have_debuginfo = _x isa Core.DebugInfo
×
UNCOV
1190
    if have_debuginfo
×
UNCOV
1191
        ci.debuginfo = _x
×
1192
    else
UNCOV
1193
        codelocs = _x::Vector{Int32}
×
1194
        # TODO: convert codelocs to debuginfo format?
1195
    end
UNCOV
1196
    _x = deserialize(s)
×
UNCOV
1197
    if _x isa Array || _x isa Int
×
UNCOV
1198
        pre_12 = false
×
1199
    else
UNCOV
1200
        pre_12 = true
×
1201
        # < v1.2
UNCOV
1202
        ci.method_for_inference_limit_heuristics = _x
×
UNCOV
1203
        _x = deserialize(s)
×
1204
    end
UNCOV
1205
    ci.ssavaluetypes = _x
×
UNCOV
1206
    if pre_12
×
UNCOV
1207
        linetable = deserialize(s)
×
1208
        # TODO: convert linetable to debuginfo format?
1209
    end
UNCOV
1210
    ssaflags = deserialize(s)
×
UNCOV
1211
    if length(ssaflags) ≠ length(code)
×
1212
        # make sure the length of `ssaflags` matches that of `code`
1213
        # so that the latest inference doesn't throw on IRs serialized from old versions
UNCOV
1214
        ssaflags = UInt32[0x00 for _ in 1:length(code)]
×
UNCOV
1215
    elseif eltype(ssaflags) != UInt32
×
1216
        ssaflags = map(UInt32, ssaflags)
×
1217
    end
UNCOV
1218
    ci.ssaflags = ssaflags
×
UNCOV
1219
    if pre_12
×
UNCOV
1220
        ci.slotflags = deserialize(s)
×
1221
    else
UNCOV
1222
        if format_version(s) <= 26
×
1223
            ci.method_for_inference_limit_heuristics = deserialize(s)
×
1224
        end
UNCOV
1225
        if !have_debuginfo # pre v1.11 format
×
1226
            linetable = deserialize(s)
×
1227
            # TODO: convert linetable to debuginfo format?
1228
        end
1229
    end
UNCOV
1230
    ci.slotnames = deserialize(s)
×
UNCOV
1231
    if !pre_12
×
UNCOV
1232
        ci.slotflags = deserialize(s)
×
UNCOV
1233
        ci.slottypes = deserialize(s)
×
UNCOV
1234
        ci.rettype = deserialize(s)
×
UNCOV
1235
        ci.parent = deserialize(s)
×
UNCOV
1236
        world_or_edges = deserialize(s)
×
UNCOV
1237
        pre_13 = isa(world_or_edges, Union{UInt, Int})
×
UNCOV
1238
        if pre_13
×
1239
            ci.min_world = reinterpret(UInt, world_or_edges)
×
1240
            ci.max_world = reinterpret(UInt, deserialize(s))
×
1241
        else
UNCOV
1242
            ci.edges = world_or_edges
×
UNCOV
1243
            ci.min_world = deserialize(s)::UInt
×
UNCOV
1244
            ci.max_world = deserialize(s)::UInt
×
1245
        end
UNCOV
1246
        if format_version(s) >= 26
×
UNCOV
1247
            ci.method_for_inference_limit_heuristics = deserialize(s)
×
1248
        end
1249
    end
UNCOV
1250
    if format_version(s) <= 26
×
UNCOV
1251
        deserialize(s)::Bool # inferred
×
1252
    end
UNCOV
1253
    if format_version(s) < 22
×
UNCOV
1254
        inlining_cost = deserialize(s)
×
UNCOV
1255
        if isa(inlining_cost, Bool)
×
UNCOV
1256
            Core.Compiler.set_inlineable!(ci, inlining_cost)
×
1257
        else
1258
            ci.inlining_cost = inlining_cost
×
1259
        end
1260
    end
UNCOV
1261
    if format_version(s) >= 29
×
UNCOV
1262
        ci.nargs = deserialize(s)
×
1263
    end
UNCOV
1264
    ci.propagate_inbounds = deserialize(s)
×
UNCOV
1265
    if format_version(s) < 23
×
UNCOV
1266
        deserialize(s) # `pure` field has been removed
×
1267
    end
UNCOV
1268
    if format_version(s) >= 20
×
UNCOV
1269
        ci.has_fcall = deserialize(s)
×
1270
    end
UNCOV
1271
    if format_version(s) >= 24
×
UNCOV
1272
        ci.nospecializeinfer = deserialize(s)::Bool
×
1273
    end
UNCOV
1274
    if format_version(s) >= 29
×
UNCOV
1275
        ci.isva = deserialize(s)::Bool
×
1276
    end
UNCOV
1277
    if format_version(s) >= 21
×
UNCOV
1278
        ci.inlining = deserialize(s)::UInt8
×
1279
    end
UNCOV
1280
    if format_version(s) >= 14
×
UNCOV
1281
        ci.constprop = deserialize(s)::UInt8
×
1282
    end
UNCOV
1283
    if format_version(s) >= 26
×
UNCOV
1284
        ci.purity = deserialize(s)::UInt16
×
UNCOV
1285
    elseif format_version(s) >= 17
×
1286
        ci.purity = deserialize(s)::UInt8
×
1287
    end
UNCOV
1288
    if format_version(s) >= 22
×
UNCOV
1289
        ci.inlining_cost = deserialize(s)::UInt16
×
1290
    end
UNCOV
1291
    ci.debuginfo = NullDebugInfo
×
UNCOV
1292
    return ci
×
1293
end
1294

1295
import Core: NullDebugInfo
1296

1297
if Int === Int64
1298
const OtherInt = Int32
1299
else
1300
const OtherInt = Int64
1301
end
1302

1303
function deserialize_array(s::AbstractSerializer)
8✔
1304
    slot = s.counter; s.counter += 1
8✔
1305
    d1 = deserialize(s)
8✔
1306
    if isa(d1, Type)
8✔
1307
        elty = d1
8✔
1308
        d1 = deserialize(s)
8✔
1309
    else
UNCOV
1310
        elty = UInt8
×
1311
    end
1312
    if isa(d1, Int32) || isa(d1, Int64)
16✔
1313
        if elty !== Bool && isbitstype(elty)
8✔
1314
            a = Vector{elty}(undef, d1)
4✔
1315
            s.table[slot] = a
4✔
1316
            return read!(s.io, a)
4✔
1317
        end
1318
        dims = (Int(d1),)
8✔
UNCOV
1319
    elseif d1 isa Dims
×
UNCOV
1320
        dims = d1::Dims
×
1321
    else
1322
        dims = convert(Dims, d1::Tuple{Vararg{OtherInt}})::Dims
×
1323
    end
1324
    if isbitstype(elty)
4✔
UNCOV
1325
        n = prod(dims)::Int
×
UNCOV
1326
        if elty === Bool && n > 0
×
UNCOV
1327
            A = Array{Bool, length(dims)}(undef, dims)
×
UNCOV
1328
            i = 1
×
UNCOV
1329
            while i <= n
×
UNCOV
1330
                b = read(s.io, UInt8)::UInt8
×
UNCOV
1331
                v = (b >> 7) != 0
×
UNCOV
1332
                count = b & 0x7f
×
UNCOV
1333
                nxt = i + count
×
UNCOV
1334
                while i < nxt
×
UNCOV
1335
                    A[i] = v
×
UNCOV
1336
                    i += 1
×
UNCOV
1337
                end
×
UNCOV
1338
            end
×
1339
        else
UNCOV
1340
            A = read!(s.io, Array{elty}(undef, dims))
×
1341
        end
UNCOV
1342
        s.table[slot] = A
×
UNCOV
1343
        return A
×
1344
    end
1345
    A = Array{elty, length(dims)}(undef, dims)
4✔
1346
    s.table[slot] = A
4✔
1347
    sizehint!(s.table, s.counter + div(length(A)::Int,4))
4✔
1348
    deserialize_fillarray!(A, s)
4✔
1349
    return A
4✔
1350
end
1351

1352
function deserialize_fillarray!(A::Union{Array{T},Memory{T}}, s::AbstractSerializer) where {T}
4✔
1353
    for i = eachindex(A)
4✔
1354
        tag = Int32(read(s.io, UInt8)::UInt8)
2✔
1355
        if tag != UNDEFREF_TAG
2✔
1356
            @inbounds A[i] = handle_deserialize(s, tag)
2✔
1357
        end
1358
    end
2✔
1359
    return A
4✔
1360
end
1361

UNCOV
1362
function deserialize(s::AbstractSerializer, X::Type{Memory{T}} where T)
×
UNCOV
1363
    slot = pop!(s.pending_refs) # e.g. deserialize_cycle
×
UNCOV
1364
    n = deserialize(s)::Int
×
UNCOV
1365
    elty = eltype(X)
×
UNCOV
1366
    if isbitstype(elty)
×
UNCOV
1367
        A = X(undef, n)
×
UNCOV
1368
        if X === Memory{Bool}
×
1369
            i = 1
×
1370
            while i <= n
×
1371
                b = read(s.io, UInt8)::UInt8
×
1372
                v = (b >> 7) != 0
×
1373
                count = b & 0x7f
×
1374
                nxt = i + count
×
1375
                while i < nxt
×
1376
                    A[i] = v
×
1377
                    i += 1
×
1378
                end
×
1379
            end
×
1380
        else
UNCOV
1381
            A = read!(s.io, A)::X
×
1382
        end
UNCOV
1383
        s.table[slot] = A
×
UNCOV
1384
        return A
×
1385
    end
1386
    A = X(undef, n)
×
1387
    s.table[slot] = A
×
1388
    sizehint!(s.table, s.counter + div(n, 4))
×
1389
    deserialize_fillarray!(A, s)
×
1390
    return A
×
1391
end
1392

1393
function deserialize(s::AbstractSerializer, X::Type{MemoryRef{T}} where T)
×
1394
    x = Core.memoryref(deserialize(s))::X
×
1395
    i = deserialize(s)::Int
×
1396
    i == 2 || (x = Core.memoryref(x, i, true))
×
1397
    return x::X
×
1398
end
1399

UNCOV
1400
function deserialize(s::AbstractSerializer, X::Type{Core.AddrSpace{M}} where M)
×
UNCOV
1401
    Core.bitcast(X, read(s.io, UInt8))
×
1402
end
1403

UNCOV
1404
function deserialize_expr(s::AbstractSerializer, len)
×
UNCOV
1405
    e = Expr(:temp)
×
UNCOV
1406
    resolve_ref_immediately(s, e)
×
UNCOV
1407
    e.head = deserialize(s)::Symbol
×
UNCOV
1408
    e.args = Any[ deserialize(s) for i = 1:len ]
×
UNCOV
1409
    e
×
1410
end
1411

1412
module __deserialized_types__ end
1413

UNCOV
1414
function deserialize(s::AbstractSerializer, ::Type{Core.TypeName})
×
UNCOV
1415
    number = read(s.io, UInt64)
×
UNCOV
1416
    return deserialize_typename(s, number)
×
1417
end
1418

UNCOV
1419
function deserialize_typename(s::AbstractSerializer, number)
×
UNCOV
1420
    name = deserialize(s)::Symbol
×
UNCOV
1421
    tn = lookup_object_number(s, number)
×
UNCOV
1422
    if tn !== nothing
×
UNCOV
1423
        makenew = false
×
1424
    else
1425
        # reuse the same name for the type, if possible, for nicer debugging
UNCOV
1426
        tn_name = isdefined(__deserialized_types__, name) ? gensym() : name
×
UNCOV
1427
        tn = ccall(:jl_new_typename_in, Any, (Any, Any, Cint, Cint),
×
1428
                   tn_name, __deserialized_types__, false, false)
UNCOV
1429
        makenew = true
×
1430
    end
UNCOV
1431
    tn = tn::Core.TypeName
×
UNCOV
1432
    remember_object(s, tn, number)
×
UNCOV
1433
    deserialize_cycle(s, tn)
×
1434

UNCOV
1435
    names = deserialize(s)::SimpleVector
×
UNCOV
1436
    super = deserialize(s)::Type
×
UNCOV
1437
    parameters = deserialize(s)::SimpleVector
×
UNCOV
1438
    types = deserialize(s)::SimpleVector
×
UNCOV
1439
    attrs = Core.svec()
×
UNCOV
1440
    has_instance = deserialize(s)::Bool
×
UNCOV
1441
    abstr = deserialize(s)::Bool
×
UNCOV
1442
    mutabl = deserialize(s)::Bool
×
UNCOV
1443
    ninitialized = deserialize(s)::Int32
×
UNCOV
1444
    maxm = format_version(s) >= 18 ? deserialize(s)::UInt8 : UInt8(0)
×
1445

UNCOV
1446
    if makenew
×
1447
        # TODO: there's an unhanded cycle in the dependency graph at this point:
1448
        # while deserializing super and/or types, we may have encountered
1449
        # tn.wrapper and throw UndefRefException before we get to this point
UNCOV
1450
        ndt = ccall(:jl_new_datatype, Any, (Any, Any, Any, Any, Any, Any, Any, Cint, Cint, Cint),
×
1451
                    tn, tn.module, super, parameters, names, types, attrs,
1452
                    abstr, mutabl, ninitialized)
UNCOV
1453
        @assert tn == ndt.name
×
UNCOV
1454
        ccall(:jl_set_const, Cvoid, (Any, Any, Any), tn.module, tn.name, tn.wrapper)
×
UNCOV
1455
        ty = tn.wrapper
×
UNCOV
1456
        tn.max_methods = maxm
×
UNCOV
1457
        if has_instance
×
UNCOV
1458
            ty = ty::DataType
×
UNCOV
1459
            if !isdefined(ty, :instance)
×
1460
                singleton = ccall(:jl_new_struct, Any, (Any, Any...), ty)
×
1461
                # use setfield! directly to avoid `fieldtype` lowering expecting to see a Singleton object already on ty
1462
                ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), ty, Base.fieldindex(DataType, :instance)-1, singleton)
×
1463
            end
1464
        end
1465
    end
1466

UNCOV
1467
    tag = Int32(read(s.io, UInt8)::UInt8)
×
UNCOV
1468
    if tag != UNDEFREF_TAG
×
UNCOV
1469
        mtname = handle_deserialize(s, tag)
×
UNCOV
1470
        defs = deserialize(s)
×
UNCOV
1471
        maxa = deserialize(s)::Int
×
UNCOV
1472
        if makenew
×
UNCOV
1473
            mt = ccall(:jl_new_method_table, Any, (Any, Any), name, tn.module)
×
UNCOV
1474
            if !isempty(parameters)
×
UNCOV
1475
                mt.offs = 0
×
1476
            end
UNCOV
1477
            mt.name = mtname
×
UNCOV
1478
            setfield!(mt, :max_args, maxa, :monotonic)
×
UNCOV
1479
            ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), tn, Base.fieldindex(Core.TypeName, :mt)-1, mt)
×
UNCOV
1480
            for def in defs
×
UNCOV
1481
                if isdefined(def, :sig)
×
UNCOV
1482
                    ccall(:jl_method_table_insert, Cvoid, (Any, Any, Ptr{Cvoid}), mt, def, C_NULL)
×
1483
                end
UNCOV
1484
            end
×
1485
        end
UNCOV
1486
        tag = Int32(read(s.io, UInt8)::UInt8)
×
UNCOV
1487
        if tag != UNDEFREF_TAG
×
UNCOV
1488
            kws = handle_deserialize(s, tag)
×
UNCOV
1489
            if makenew && !(kws isa Vector{Method})
×
1490
                # old object format -- try to forward from old to new
1491
                @eval Core.kwcall(kwargs::NamedTuple, f::$ty, args...) = $kws(kwargs, f, args...)
×
1492
            end
1493
        end
UNCOV
1494
    elseif makenew
×
UNCOV
1495
        mt = Symbol.name.mt
×
UNCOV
1496
        ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), tn, Base.fieldindex(Core.TypeName, :mt)-1, mt)
×
1497
    end
UNCOV
1498
    return tn
×
1499
end
1500

1501
function deserialize_datatype(s::AbstractSerializer, full::Bool)
30✔
1502
    slot = s.counter; s.counter += 1
30✔
1503
    if full
30✔
UNCOV
1504
        tname = deserialize(s)::Core.TypeName
×
UNCOV
1505
        ty = tname.wrapper
×
1506
    else
1507
        name = deserialize(s)::Symbol
30✔
1508
        mod = deserialize(s)::Module
30✔
1509
        ty = getglobal(mod, name)
30✔
1510
    end
1511
    if isa(ty,DataType) && isempty(ty.parameters)
30✔
1512
        t = ty
10✔
1513
    else
1514
        np = Int(read(s.io, Int32)::Int32)
20✔
1515
        if np == 0
20✔
UNCOV
1516
            t = unwrap_unionall(ty)
×
1517
        elseif ty === Tuple
20✔
1518
            # note np==0 has its own tag
UNCOV
1519
            if np == 1
×
UNCOV
1520
                t = Tuple{deserialize(s)}
×
UNCOV
1521
            elseif np == 2
×
UNCOV
1522
                t = Tuple{deserialize(s), deserialize(s)}
×
UNCOV
1523
            elseif np == 3
×
UNCOV
1524
                t = Tuple{deserialize(s), deserialize(s), deserialize(s)}
×
1525
            elseif np == 4
×
1526
                t = Tuple{deserialize(s), deserialize(s), deserialize(s), deserialize(s)}
×
1527
            else
1528
                t = Tuple{Any[ deserialize(s) for i=1:np ]...}
×
1529
            end
1530
        else
1531
            t = ty
20✔
1532
            for i = 1:np
20✔
1533
                t = t{deserialize(s)}
60✔
1534
            end
60✔
1535
        end
1536
    end
1537
    s.table[slot] = t
30✔
1538
    return t
30✔
1539
end
1540

UNCOV
1541
function deserialize(s::AbstractSerializer, ::Type{UnionAll})
×
UNCOV
1542
    form = read(s.io, UInt8)
×
UNCOV
1543
    if form == 0
×
UNCOV
1544
        var = deserialize(s)
×
UNCOV
1545
        body = deserialize(s)
×
UNCOV
1546
        return UnionAll(var, body)
×
1547
    else
UNCOV
1548
        n = read(s.io, Int16)
×
UNCOV
1549
        t = deserialize(s)::DataType
×
UNCOV
1550
        w = t.name.wrapper
×
UNCOV
1551
        k = 0
×
UNCOV
1552
        while isa(w, UnionAll)
×
UNCOV
1553
            w = w.body
×
UNCOV
1554
            k += 1
×
UNCOV
1555
        end
×
UNCOV
1556
        w = t.name.wrapper
×
UNCOV
1557
        k -= n
×
UNCOV
1558
        while k > 0
×
1559
            w = w.body
×
1560
            k -= 1
×
1561
        end
×
UNCOV
1562
        return w
×
1563
    end
1564
end
1565

UNCOV
1566
function deserialize(s::AbstractSerializer, ::Type{Task})
×
UNCOV
1567
    t = Task(()->nothing)
×
UNCOV
1568
    deserialize_cycle(s, t)
×
UNCOV
1569
    t.code = deserialize(s)
×
UNCOV
1570
    t.storage = deserialize(s)
×
UNCOV
1571
    state = deserialize(s)
×
UNCOV
1572
    if state === :runnable
×
1573
        @atomic :release t._state = Base.task_state_runnable
×
UNCOV
1574
    elseif state === :done
×
UNCOV
1575
        @atomic :release t._state = Base.task_state_done
×
UNCOV
1576
    elseif state === :failed
×
UNCOV
1577
        @atomic :release t._state = Base.task_state_failed
×
1578
    else
1579
        @assert false
×
1580
    end
UNCOV
1581
    t.result = deserialize(s)
×
UNCOV
1582
    exc = deserialize(s)
×
UNCOV
1583
    if exc === nothing
×
1584
        t._isexception = false
×
UNCOV
1585
    elseif exc isa Bool
×
UNCOV
1586
        t._isexception = exc
×
1587
    else
1588
        t._isexception = true
×
1589
        t.result = exc
×
1590
    end
UNCOV
1591
    t
×
1592
end
1593

1594
function deserialize_string(s::AbstractSerializer, len::Int)
1595
    out = ccall(:jl_alloc_string, Ref{String}, (Csize_t,), len)
2✔
1596
    unsafe_read(s.io, pointer(out), len)
2✔
1597
    return out
2✔
1598
end
1599

1600
# default DataType deserializer
1601
function deserialize(s::AbstractSerializer, t::DataType)
30✔
1602
    nf = length(t.types)
30✔
1603
    if isprimitivetype(t)
30✔
UNCOV
1604
        return read(s.io, t)
×
1605
    elseif ismutabletype(t)
30✔
UNCOV
1606
        x = ccall(:jl_new_struct_uninit, Any, (Any,), t)
×
UNCOV
1607
        deserialize_cycle(s, x)
×
UNCOV
1608
        for i in 1:nf
×
UNCOV
1609
            tag = Int32(read(s.io, UInt8)::UInt8)
×
UNCOV
1610
            if tag != UNDEFREF_TAG
×
UNCOV
1611
                ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), x, i-1, handle_deserialize(s, tag))
×
1612
            end
UNCOV
1613
        end
×
UNCOV
1614
        return x
×
1615
    elseif nf == 0
30✔
1616
        return ccall(:jl_new_struct_uninit, Any, (Any,), t)
20✔
1617
    else
1618
        na = nf
10✔
1619
        vflds = Vector{Any}(undef, nf)
10✔
1620
        for i in 1:nf
10✔
1621
            tag = Int32(read(s.io, UInt8)::UInt8)
20✔
1622
            if tag != UNDEFREF_TAG
20✔
1623
                f = handle_deserialize(s, tag)
20✔
1624
                na >= i && (vflds[i] = f)
20✔
1625
            else
UNCOV
1626
                na >= i && (na = i - 1) # rest of tail must be undefined values
×
1627
            end
1628
        end
30✔
1629
        return ccall(:jl_new_structv, Any, (Any, Ptr{Any}, UInt32), t, vflds, na)
10✔
1630
    end
1631
end
1632

UNCOV
1633
function deserialize_dict(s::AbstractSerializer, T::Type{<:AbstractDict})
×
UNCOV
1634
    n = read(s.io, Int32)
×
UNCOV
1635
    t = T(); sizehint!(t, n)
×
UNCOV
1636
    deserialize_cycle(s, t)
×
UNCOV
1637
    for i = 1:n
×
UNCOV
1638
        k = deserialize(s)
×
UNCOV
1639
        v = deserialize(s)
×
UNCOV
1640
        t[k] = v
×
UNCOV
1641
    end
×
UNCOV
1642
    return t
×
1643
end
1644

UNCOV
1645
function deserialize(s::AbstractSerializer, T::Type{Dict{K,V}}) where {K,V}
×
UNCOV
1646
    return deserialize_dict(s, T)
×
1647
end
1648

UNCOV
1649
deserialize(s::AbstractSerializer, ::Type{BigInt}) = parse(BigInt, deserialize(s), base = 62)
×
1650

UNCOV
1651
function deserialize(s::AbstractSerializer, t::Type{Regex})
×
UNCOV
1652
    pattern = deserialize(s)
×
UNCOV
1653
    compile_options = deserialize(s)
×
UNCOV
1654
    match_options = deserialize(s)
×
UNCOV
1655
    return Regex(pattern, compile_options, match_options)
×
1656
end
1657

1658
## StackTraces
1659

1660
# provide a custom serializer that skips attempting to serialize the `outer_linfo`
1661
# which is likely to contain complex references, types, and module references
1662
# that may not exist on the receiver end
UNCOV
1663
function serialize(s::AbstractSerializer, frame::Base.StackTraces.StackFrame)
×
UNCOV
1664
    serialize_type(s, typeof(frame))
×
UNCOV
1665
    serialize(s, frame.func)
×
UNCOV
1666
    serialize(s, frame.file)
×
UNCOV
1667
    write(s.io, frame.line)
×
UNCOV
1668
    write(s.io, frame.from_c)
×
UNCOV
1669
    write(s.io, frame.inlined)
×
UNCOV
1670
    write(s.io, frame.pointer)
×
UNCOV
1671
    nothing
×
1672
end
1673

UNCOV
1674
function deserialize(s::AbstractSerializer, ::Type{Base.StackTraces.StackFrame})
×
UNCOV
1675
    func = deserialize(s)
×
UNCOV
1676
    file = deserialize(s)
×
UNCOV
1677
    line = read(s.io, Int)
×
UNCOV
1678
    from_c = read(s.io, Bool)
×
UNCOV
1679
    inlined = read(s.io, Bool)
×
UNCOV
1680
    pointer = read(s.io, UInt64)
×
UNCOV
1681
    return Base.StackTraces.StackFrame(func, file, line, nothing, from_c, inlined, pointer)
×
1682
end
1683

UNCOV
1684
function serialize(s::AbstractSerializer, lock::Base.AbstractLock)
×
1685
    # assert_havelock(lock)
UNCOV
1686
    serialize_cycle_header(s, lock)
×
UNCOV
1687
    nothing
×
1688
end
1689

UNCOV
1690
function deserialize(s::AbstractSerializer, ::Type{T}) where T<:Base.AbstractLock
×
UNCOV
1691
    lock = T()
×
UNCOV
1692
    deserialize_cycle(s, lock)
×
UNCOV
1693
    return lock
×
1694
end
1695

UNCOV
1696
function serialize(s::AbstractSerializer, cond::Base.GenericCondition)
×
UNCOV
1697
    serialize_cycle_header(s, cond) && return
×
UNCOV
1698
    serialize(s, cond.lock)
×
UNCOV
1699
    nothing
×
1700
end
1701

UNCOV
1702
function deserialize(s::AbstractSerializer, ::Type{T}) where T<:Base.GenericCondition
×
UNCOV
1703
    lock = deserialize(s)
×
UNCOV
1704
    cond = T(lock)
×
UNCOV
1705
    deserialize_cycle(s, cond)
×
UNCOV
1706
    return cond
×
1707
end
1708

UNCOV
1709
serialize(s::AbstractSerializer, l::LazyString) =
×
1710
    invoke(serialize, Tuple{AbstractSerializer,Any}, s, Base._LazyString((), string(l)))
1711

1712
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc