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

JuliaLang / julia / 1391

29 Dec 2025 07:41PM UTC coverage: 76.638% (+0.02%) from 76.621%
1391

push

buildkite

web-flow
🤖 Bump StyledStrings stdlib 9bb8ffd → a033d46 (#60503)

Co-authored-by: KristofferC <1282691+KristofferC@users.noreply.github.com>

62409 of 81433 relevant lines covered (76.64%)

22974996.93 hits per line

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

88.41
/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 Base.ScopedValues: ScopedValue, with
12
import Core: svec, SimpleVector
13
using Base: unaliascopy, unwrap_unionall, require_one_based_indexing, ntupleany
14
using Core.IR
15

16
export serialize, deserialize, AbstractSerializer, Serializer
17

18
abstract type AbstractSerializer end
19

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

30
Serializer(io::IO) = Serializer{typeof(io)}(io)
2,309✔
31

32
const current_module = ScopedValue{Union{Nothing,Module}}(nothing)
33

34
## serializing values ##
35

36
const n_int_literals = 33
37
const n_reserved_slots = 24
38
const n_reserved_tags = 8
39

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

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

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

77
    fill(:_reserved_, n_reserved_slots)...,
78

79
    (Int32(0):Int32(n_int_literals-1))...,
80
    (Int64(0):Int64(n_int_literals-1))...
81
]
82

83
const NTAGS = length(TAGS)
84
@assert NTAGS == 255
85

86
const ser_version = 30 # do not make changes without bumping the version #!
87

88
format_version(::AbstractSerializer) = ser_version
26,397✔
89
format_version(s::Serializer) = s.version
744✔
90

91
function sertag(@nospecialize(v))
9✔
92
    # NOTE: we use jl_value_ptr directly since we know at least one of the arguments
93
    # in the comparison below is a singleton.
94
    ptr = ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), v)
3,369,440✔
95
    ptags = convert(Ptr{Ptr{Cvoid}}, pointer(TAGS))
3,369,440✔
96
    # note: constant ints & reserved slots never returned here
97
    @inbounds for i in 1:(NTAGS-(n_reserved_slots+2*n_int_literals))
3,369,440✔
98
        ptr == unsafe_load(ptags,i) && return i%Int32
501,584,559✔
99
    end
999,081,086✔
100
    return Int32(-1)
2,650,848✔
101
end
102
desertag(i::Int32) = @inbounds(TAGS[i])
1,316,480✔
103

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

148
writetag(s::IO, tag) = (write(s, UInt8(tag)); nothing)
15,563,655✔
149

150
function write_as_tag(s::IO, tag)
70,179✔
151
    tag < VALUE_TAGS && write(s, UInt8(0))
746,647✔
152
    write(s, UInt8(tag))
816,349✔
153
    nothing
746,170✔
154
end
155

156
# cycle handling
157
function serialize_cycle(s::AbstractSerializer, @nospecialize(x))
7,724,169✔
158
    offs = get(s.table, x, -1)::Int
7,724,169✔
159
    if offs != -1
7,724,169✔
160
        if offs <= typemax(UInt16)
5,513,006✔
161
            writetag(s.io, SHORTBACKREF_TAG)
5,513,264✔
162
            write(s.io, UInt16(offs))
5,513,003✔
163
        elseif offs <= typemax(Int32)
3✔
164
            writetag(s.io, BACKREF_TAG)
3✔
165
            write(s.io, Int32(offs))
3✔
166
        else
167
            writetag(s.io, LONGBACKREF_TAG)
×
168
            write(s.io, Int64(offs))
×
169
        end
170
        return true
5,513,006✔
171
    end
172
    s.table[x] = s.counter
2,211,163✔
173
    s.counter += 1
2,211,163✔
174
    return false
2,211,163✔
175
end
176

177
function serialize_cycle_header(s::AbstractSerializer, @nospecialize(x))
178
    serialize_cycle(s, x) && return true
1,508,281✔
179
    serialize_type(s, typeof(x), true)
687,139✔
180
    return false
687,139✔
181
end
182

183
function reset_state(s::AbstractSerializer)
103,548✔
184
    s.counter = 0
202,348✔
185
    empty!(s.table)
202,348✔
186
    empty!(s.pending_refs)
202,348✔
187
    s
202,348✔
188
end
189

190
serialize(s::AbstractSerializer, x::Bool) = x ? writetag(s.io, TRUE_TAG) :
39,438✔
191
                                                writetag(s.io, FALSE_TAG)
192

193
serialize(s::AbstractSerializer, p::Ptr) = serialize_any(s, oftype(p, C_NULL))
56✔
194

195
serialize(s::AbstractSerializer, ::Tuple{}) = writetag(s.io, EMPTYTUPLE_TAG)
85,234✔
196

197
function serialize(s::AbstractSerializer, t::Tuple)
47,908✔
198
    l = length(t)
48,194✔
199
    if l <= NTAGS
48,194✔
200
        writetag(s.io, TUPLE_TAG)
48,272✔
201
        write(s.io, UInt8(l))
48,272✔
202
    else
203
        writetag(s.io, LONGTUPLE_TAG)
6✔
204
        write(s.io, Int32(l))
3✔
205
    end
206
    for x in t
48,194✔
207
        serialize(s, x)
126,147✔
208
    end
92,009✔
209
end
210

211
function serialize(s::AbstractSerializer, v::SimpleVector)
6,568✔
212
    writetag(s.io, SIMPLEVECTOR_TAG)
6,694✔
213
    write(s.io, Int32(length(v)))
6,568✔
214
    for x in v
7,487✔
215
        serialize(s, x)
1,402✔
216
    end
1,402✔
217
end
218

219
function serialize(s::AbstractSerializer, x::Symbol)
586,041✔
220
    tag = sertag(x)
94,002,037✔
221
    if tag > 0
586,041✔
222
        return write_as_tag(s.io, tag)
210,163✔
223
    end
224
    pname = unsafe_convert(Ptr{UInt8}, x)
375,878✔
225
    len = Int(ccall(:strlen, Csize_t, (Cstring,), pname))
375,878✔
226
    if len > 7
375,878✔
227
        serialize_cycle(s, x) && return
186,965✔
228
    end
229
    if len <= NTAGS
349,673✔
230
        writetag(s.io, SYMBOL_TAG)
350,487✔
231
        write(s.io, UInt8(len))
350,487✔
232
    else
233
        writetag(s.io, LONGSYMBOL_TAG)
6✔
234
        write(s.io, Int32(len))
3✔
235
    end
236
    unsafe_write(s.io, pname, len)
349,673✔
237
    nothing
349,673✔
238
end
239

240
function serialize_array_data(s::IO, a)
3✔
241
    require_one_based_indexing(a)
8,153✔
242
    isempty(a) && return 0
8,153✔
243
    if eltype(a) === Bool
8,125✔
244
        last = a[1]::Bool
3✔
245
        count = 1
3✔
246
        for i = 2:length(a)
3✔
247
            if a[i]::Bool != last || count == 127
36✔
248
                write(s, UInt8((UInt8(last) << 7) | count))
24✔
249
                last = a[i]::Bool
12✔
250
                count = 1
12✔
251
            else
252
                count += 1
12✔
253
            end
254
        end
45✔
255
        write(s, UInt8((UInt8(last) << 7) | count))
3✔
256
    else
257
        write(s, a)
8,122✔
258
    end
259
end
260

261
function serialize(s::AbstractSerializer, a::Array)
27,585✔
262
    serialize_cycle(s, a) && return
27,588✔
263
    elty = eltype(a)
27,555✔
264
    writetag(s.io, ARRAY_TAG)
27,849✔
265
    if elty !== UInt8
27,555✔
266
        serialize(s, elty)
26,256✔
267
    end
268
    if ndims(a) != 1
27,555✔
269
        serialize(s, size(a))
333✔
270
    else
271
        serialize(s, length(a))
27,363✔
272
    end
273
    if isbitstype(elty)
27,555✔
274
        serialize_array_data(s.io, a)
8,065✔
275
    else
276
        sizehint!(s.table, div(length(a),4))  # prepare for lots of pointers
20,069✔
277
        @inbounds for i in eachindex(a)
24,353✔
278
            if isassigned(a, i)
1,290,369✔
279
                serialize(s, a[i])
1,865,110✔
280
            else
281
                writetag(s.io, UNDEFREF_TAG)
6✔
282
            end
283
        end
1,290,369✔
284
    end
285
end
286

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

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

313
function serialize(s::AbstractSerializer, x::GenericMemoryRef)
×
314
    serialize_type(s, typeof(x))
×
315
    serialize(s, getfield(x, :mem))
×
316
    serialize(s, Base.memoryrefoffset(x))
×
317
end
318

319
function serialize(s::AbstractSerializer, ss::String)
8,629,632✔
320
    len = sizeof(ss)
8,629,632✔
321
    if len > 7
8,629,632✔
322
        serialize_cycle(s, ss) && return
4,434,869✔
323
        writetag(s.io, SHARED_REF_TAG)
1,050,546✔
324
    end
325
    if len <= NTAGS
5,245,262✔
326
        writetag(s.io, STRING_TAG)
5,225,403✔
327
        write(s.io, UInt8(len))
5,225,403✔
328
    else
329
        writetag(s.io, LONGSTRING_TAG)
19,948✔
330
        write(s.io, Int64(len))
19,945✔
331
    end
332
    write(s.io, ss)
5,245,262✔
333
    nothing
5,245,262✔
334
end
335

336
function serialize(s::AbstractSerializer, ss::SubString{String})
10,263✔
337
    # avoid saving a copy of the parent string, keeping the type of ss
338
    serialize_any(s, SubString(String(ss)))
10,263✔
339
end
340

341
# Don't serialize the pointers
342
function serialize(s::AbstractSerializer, r::Regex)
3✔
343
    serialize_type(s, typeof(r))
3✔
344
    serialize(s, r.pattern)
3✔
345
    serialize(s, r.compile_options)
6✔
346
    serialize(s, r.match_options)
3✔
347
end
348

349
function serialize(s::AbstractSerializer, n::BigInt)
350
    serialize_type(s, BigInt)
3✔
351
    serialize(s, string(n, base = 62))
3✔
352
end
353

354
function serialize(s::AbstractSerializer, ex::Expr)
12,322✔
355
    serialize_cycle(s, ex) && return
12,322✔
356
    l = length(ex.args)
12,322✔
357
    if l <= NTAGS
12,322✔
358
        writetag(s.io, EXPR_TAG)
13,282✔
359
        write(s.io, UInt8(l))
13,282✔
360
    else
361
        writetag(s.io, LONGEXPR_TAG)
6✔
362
        write(s.io, Int32(l))
3✔
363
    end
364
    serialize(s, ex.head)
12,322✔
365
    for a in ex.args
12,322✔
366
        serialize(s, a)
29,235✔
367
    end
29,235✔
368
end
369

370
function serialize_dict_data(s::AbstractSerializer, d::AbstractDict)
685,950✔
371
    write(s.io, Int32(length(d)))
685,950✔
372
    for (k,v) in d
1,371,896✔
373
        serialize(s, k)
4,843,027✔
374
        serialize(s, v)
4,843,027✔
375
    end
4,843,027✔
376
end
377

378
function serialize(s::AbstractSerializer, d::Dict)
1,003,673✔
379
    serialize_cycle_header(s, d) && return
2,193,024✔
380
    serialize_dict_data(s, d)
685,944✔
381
end
382

383
function serialize(s::AbstractSerializer, d::IdDict)
6✔
384
    serialize_cycle(s, d) && return
6✔
385
    writetag(s.io, IDDICT_TAG)
12✔
386
    serialize_type_data(s, typeof(d))
6✔
387
    serialize_dict_data(s, d)
6✔
388
end
389

390
function serialize_mod_names(s::AbstractSerializer, m::Module)
262,934✔
391
    p = parentmodule(m)
262,934✔
392
    if p === m || m === Base
336,165✔
393
        key = Base.root_module_key(m)
261,281✔
394
        uuid = key.uuid
261,281✔
395
        serialize(s, uuid === nothing ? nothing : uuid.value)
327,865✔
396
        serialize(s, Symbol(key.name))
261,281✔
397
    else
398
        serialize_mod_names(s, p)
1,653✔
399
        serialize(s, nameof(m))
1,653✔
400
    end
401
end
402

403
function serialize(s::AbstractSerializer, m::Module)
255,250✔
404
    writetag(s.io, MODULE_TAG)
261,775✔
405
    serialize_mod_names(s, m)
261,281✔
406
    writetag(s.io, EMPTYTUPLE_TAG)
261,281✔
407
end
408

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

423
lookup_object_number(s::AbstractSerializer, n::UInt64) = nothing
×
424

425
remember_object(s::AbstractSerializer, @nospecialize(o), n::UInt64) = nothing
×
426

427
function lookup_object_number(s::Serializer, n::UInt64)
428
    return get(s.known_object_data, n, nothing)
63✔
429
end
430

431
function remember_object(s::Serializer, @nospecialize(o), n::UInt64)
432
    s.known_object_data[n] = o
54✔
433
    return nothing
54✔
434
end
435

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

473
function serialize(s::AbstractSerializer, mt::Core.MethodTable)
×
474
    serialize_type(s, typeof(mt))
×
475
    serialize(s, mt.name)
×
476
    serialize(s, mt.module)
×
477
    nothing
×
478
end
479

480
function serialize(s::AbstractSerializer, mc::Core.MethodCache)
×
481
    error("cannot serialize MethodCache objects")
×
482
end
483

484

485
function serialize(s::AbstractSerializer, linfo::Core.MethodInstance)
×
486
    serialize_cycle(s, linfo) && return
×
487
    writetag(s.io, METHODINSTANCE_TAG)
×
488
    serialize(s, nothing)  # for backwards compat
×
489
    serialize(s, linfo.sparam_vals)
×
490
    serialize(s, Any)  # for backwards compat
×
491
    serialize(s, linfo.specTypes)
×
492
    serialize(s, linfo.def)
×
493
    nothing
×
494
end
495

496
function serialize(s::AbstractSerializer, t::Task)
9✔
497
    serialize_cycle(s, t) && return
9✔
498
    if istaskstarted(t) && !istaskdone(t)
9✔
499
        error("cannot serialize a running Task")
×
500
    end
501
    writetag(s.io, TASK_TAG)
15✔
502
    serialize(s, t.code)
9✔
503
    serialize(s, t.storage)
9✔
504
    serialize(s, t.state)
18✔
505
    if t._isexception && (stk = Base.current_exceptions(t); !isempty(stk))
9✔
506
        # the exception stack field is hidden inside the task, so if there
507
        # is any information there make a CapturedException from it instead.
508
        # TODO: Handle full exception chain, not just the first one.
509
        serialize(s, CapturedException(stk[1].exception, stk[1].backtrace))
6✔
510
    else
511
        serialize(s, t.result)
3✔
512
    end
513
    serialize(s, t._isexception)
9✔
514
end
515

516
function serialize(s::AbstractSerializer, g::GlobalRef)
5,128✔
517
    if (g.mod === __deserialized_types__ ) ||
10,253✔
518
        (g.mod === Main && isdefined(g.mod, g.name) && isconst(g.mod, g.name))
519

520
        v = getglobal(g.mod, g.name)
1,716✔
521
        unw = unwrap_unionall(v)
1,716✔
522
        if isa(unw,DataType) && v === unw.name.wrapper && should_send_whole_type(s, unw)
1,821✔
523
            # handle references to types in Main by sending the whole type.
524
            # needed to be able to send nested functions (#15451).
525
            writetag(s.io, FULL_GLOBALREF_TAG)
45✔
526
            serialize(s, v)
42✔
527
            return
42✔
528
        end
529
    end
530
    writetag(s.io, GLOBALREF_TAG)
5,125✔
531
    serialize(s, g.mod)
5,086✔
532
    serialize(s, g.name)
5,086✔
533
end
534

535
function serialize(s::AbstractSerializer, t::Core.TypeName)
60✔
536
    serialize_cycle(s, t) && return
60✔
537
    writetag(s.io, TYPENAME_TAG)
48✔
538
    write(s.io, object_number(s, t))
45✔
539
    serialize_typename(s, t)
24✔
540
end
541

542
function serialize_typename(s::AbstractSerializer, t::Core.TypeName)
1,281✔
543
    serialize(s, t.name)
1,281✔
544
    serialize(s, t.names)
1,281✔
545
    primary = unwrap_unionall(t.wrapper)
1,281✔
546
    serialize(s, primary.super)
1,281✔
547
    serialize(s, primary.parameters)
1,281✔
548
    serialize(s, primary.types)
1,281✔
549
    serialize(s, Base.issingletontype(primary))
1,533✔
550
    serialize(s, t.flags & 0x1 == 0x1) # .abstract
2,538✔
551
    serialize(s, t.flags & 0x2 == 0x2) # .mutable
2,538✔
552
    serialize(s, Int32(length(primary.types) - t.n_uninitialized))
1,281✔
553
    serialize(s, t.max_methods)
1,281✔
554
    ms = Base.matches_to_methods(Base._methods_by_ftype(Tuple{t.wrapper, Vararg}, -1, Base.get_world_counter()), t, nothing).ms
1,281✔
555
    if t.singletonname !== t.name || !isempty(ms)
1,281✔
556
        serialize(s, t.singletonname)
1,281✔
557
        serialize(s, ms)
1,281✔
558
        serialize(s, t.max_args)
1,281✔
559
        kws = Base.matches_to_methods(Base._methods_by_ftype(Tuple{typeof(Core.kwcall), Any, t.wrapper, Vararg}, -1, Base.get_world_counter()), t, nothing).ms
1,281✔
560
        if isempty(kws)
1,281✔
561
            writetag(s.io, UNDEFREF_TAG)
1,299✔
562
        else
563
            serialize(s, kws)
3✔
564
        end
565
    else
566
        writetag(s.io, UNDEFREF_TAG)
×
567
    end
568
    nothing
1,281✔
569
end
570

571
# decide whether to send all data for a type (instead of just its name)
572
function should_send_whole_type(s, t::DataType)
573
    tn = t.name
1,539,673✔
574
    # TODO improve somehow?
575
    # send whole type for anonymous functions in Main
576
    name = tn.singletonname
1,539,673✔
577
    mod = tn.module
1,539,673✔
578
    mod === __deserialized_types__ && return true
1,539,673✔
579
    isanonfunction = mod === Main && # only Main
1,540,638✔
580
        t.super === Function && # only Functions
581
        unsafe_load(unsafe_convert(Ptr{UInt8}, tn.name)) == UInt8('#') && # hidden type
582
        (!isdefined(mod, name) || t != typeof(getglobal(mod, name))) # XXX: 95% accurate test for this being an inner function
583
        # TODO: more accurate test? (tn.name !== "#" name)
584
    return isanonfunction
1,539,350✔
585
end
586

587
function serialize_type_data(s, @nospecialize(t::DataType))
1,539,565✔
588
    whole = should_send_whole_type(s, t)
3,078,810✔
589
    iswrapper = (t === unwrap_unionall(t.name.wrapper))
1,539,565✔
590
    if whole && iswrapper
1,539,565✔
591
        writetag(s.io, WRAPPER_DATATYPE_TAG)
5,430✔
592
        serialize(s, t.name)
5,376✔
593
        return
5,376✔
594
    end
595
    serialize_cycle(s, t) && return
1,534,189✔
596
    if whole
255,029✔
597
        writetag(s.io, FULL_DATATYPE_TAG)
1,040✔
598
        serialize(s, t.name)
1,034✔
599
    else
600
        writetag(s.io, DATATYPE_TAG)
254,414✔
601
        serialize(s, nameof(t))
253,995✔
602
        serialize(s, parentmodule(t))
253,995✔
603
    end
604
    if !isempty(t.parameters)
255,029✔
605
        if iswrapper
133,826✔
606
            write(s.io, Int32(0))
12✔
607
        else
608
            write(s.io, Int32(length(t.parameters)))
133,814✔
609
            for p in t.parameters
267,628✔
610
                serialize(s, p)
353,527✔
611
            end
353,527✔
612
        end
613
    end
614
    nothing
255,029✔
615
end
616

617
function serialize(s::AbstractSerializer, t::DataType)
278,659✔
618
    tag = sertag(t)
27,327,400✔
619
    tag > 0 && return write_as_tag(s.io, tag)
278,659✔
620
    if t === Tuple
131,204✔
621
        # `sertag` is not able to find types === to `Tuple` because they
622
        # will not have been hash-consed. Plus `serialize_type_data` does not
623
        # handle this case correctly, since Tuple{} != Tuple. `Tuple` is the
624
        # only type with this property. issue #15849
625
        return write_as_tag(s.io, TUPLE_TAG)
×
626
    end
627
    serialize_type_data(s, t)
131,204✔
628
end
629

630
function serialize_type(s::AbstractSerializer, @nospecialize(t::DataType), ref::Bool = false)
1,433,743✔
631
    tag = sertag(t)
234,645,086✔
632
    tag > 0 && return writetag(s.io, tag)
1,433,494✔
633
    writetag(s.io, ref ? REF_OBJECT_TAG : OBJECT_TAG)
1,408,684✔
634
    serialize_type_data(s, t)
1,408,355✔
635
end
636

637
function serialize(s::AbstractSerializer, n::Int32)
1,399✔
638
    if 0 <= n <= (n_int_literals-1)
5,170✔
639
        write(s.io, UInt8(ZERO32_TAG+n))
4,011✔
640
    else
641
        writetag(s.io, INT32_TAG)
1,273✔
642
        write(s.io, n)
1,246✔
643
    end
644
    nothing
5,170✔
645
end
646

647
function serialize(s::AbstractSerializer, n::Int64)
215,605✔
648
    if 0 <= n <= (n_int_literals-1)
215,605✔
649
        write(s.io, UInt8(ZERO64_TAG+n))
161,567✔
650
    elseif typemin(Int32) <= n <= typemax(Int32)
55,751✔
651
        writetag(s.io, SHORTINT64_TAG)
55,319✔
652
        write(s.io, Int32(n))
55,284✔
653
    else
654
        writetag(s.io, INT64_TAG)
467✔
655
        write(s.io, n)
467✔
656
    end
657
    nothing
215,605✔
658
end
659

660
for i in 0:13
661
    tag = Int32(INT8_TAG + i)
662
    ty = TAGS[tag]
663
    (ty === Int32 || ty === Int64) && continue
664
    @eval serialize(s::AbstractSerializer, n::$ty) = (writetag(s.io, $tag); write(s.io, n); nothing)
902,072✔
665
end
666

667
serialize(s::AbstractSerializer, ::Type{Bottom}) = write_as_tag(s.io, BOTTOM_TAG)
52,738✔
668

669
function serialize(s::AbstractSerializer, u::UnionAll)
279✔
670
    writetag(s.io, UNIONALL_TAG)
315✔
671
    n = 0; t = u
279✔
672
    while isa(t, UnionAll)
720✔
673
        t = t.body
441✔
674
        n += 1
441✔
675
    end
441✔
676
    if isa(t, DataType) && t === unwrap_unionall(t.name.wrapper)
279✔
677
        write(s.io, UInt8(1))
303✔
678
        write(s.io, Int16(n))
273✔
679
        serialize(s, t)
273✔
680
    else
681
        write(s.io, UInt8(0))
12✔
682
        serialize(s, u.var)
6✔
683
        serialize(s, u.body)
6✔
684
    end
685
end
686

687
serialize(s::AbstractSerializer, @nospecialize(x)) = serialize_any(s, x)
1,060,858✔
688

689
function serialize(s::AbstractSerializer, x::Core.AddrSpace)
82✔
690
    serialize_type(s, typeof(x))
82✔
691
    write(s.io, Core.bitcast(UInt8, x))
82✔
692
end
693

694
function serialize_any(s::AbstractSerializer, @nospecialize(x))
1,071,219✔
695
    tag = sertag(x)
148,271,250✔
696
    if tag > 0
1,071,219✔
697
        return write_as_tag(s.io, tag)
335,808✔
698
    end
699
    t = typeof(x)::DataType
735,411✔
700
    if isprimitivetype(t)
735,411✔
701
        serialize_type(s, t)
245✔
702
        write(s.io, x)
245✔
703
    else
704
        if ismutable(x)
735,166✔
705
            serialize_cycle(s, x) && return
12,246✔
706
            serialize_type(s, t, true)
11,800✔
707
        else
708
            serialize_type(s, t, false)
722,920✔
709
        end
710
        nf = nfields(x)
734,720✔
711
        for i in 1:nf
827,149✔
712
            if isdefined(x, i)
826,216✔
713
                serialize(s, getfield(x, i))
826,204✔
714
            else
715
                writetag(s.io, UNDEFREF_TAG)
12✔
716
            end
717
        end
826,216✔
718
    end
719
    nothing
734,965✔
720
end
721

722
"""
723
    Serialization.writeheader(s::AbstractSerializer)
724

725
Write an identifying header to the specified serializer. The header consists of
726
8 bytes as follows:
727

728
| Offset | Description                                     |
729
|:-------|:------------------------------------------------|
730
|   0    | tag byte (0x37)                                 |
731
|   1-2  | signature bytes "JL"                            |
732
|   3    | protocol version                                |
733
|   4    | bits 0-1: endianness: 0 = little, 1 = big       |
734
|   4    | bits 2-3: platform: 0 = 32-bit, 1 = 64-bit      |
735
|   5-7  | reserved                                        |
736
"""
737
function writeheader(s::AbstractSerializer)
1,143✔
738
    io = s.io
1,143✔
739
    writetag(io, HEADER_TAG)
1,439✔
740
    write(io, "JL")  # magic bytes
1,143✔
741
    write(io, UInt8(ser_version))
1,439✔
742
    endianness = (ENDIAN_BOM == 0x04030201 ? 0 :
1,143✔
743
                  ENDIAN_BOM == 0x01020304 ? 1 :
744
                  error("unsupported endianness in serializer"))
745
    machine = (sizeof(Int) == 4 ? 0 :
1,143✔
746
               sizeof(Int) == 8 ? 1 :
747
               error("unsupported word size in serializer"))
748
    write(io, UInt8(endianness) | (UInt8(machine) << 2))
1,439✔
749
    write(io, [0x00,0x00,0x00]) # 3 reserved bytes
3,429✔
750
    nothing
1,143✔
751
end
752

753
function readheader(s::AbstractSerializer)
1,169✔
754
    # Tag already read
755
    io = s.io
1,169✔
756
    m1 = read(io, UInt8)
1,169✔
757
    m2 = read(io, UInt8)
1,169✔
758
    if m1 != UInt8('J') || m2 != UInt8('L')
2,338✔
759
        error("Unsupported serialization format (got header magic bytes $m1 $m2)")
×
760
    end
761
    version    = read(io, UInt8)
1,169✔
762
    flags      = read(io, UInt8)
1,169✔
763
    reserved1  = read(io, UInt8)
1,169✔
764
    reserved2  = read(io, UInt8)
1,169✔
765
    reserved3  = read(io, UInt8)
1,169✔
766
    endianflag = flags & 0x3
1,169✔
767
    wordflag   = (flags >> 2) & 0x3
1,169✔
768
    wordsize = wordflag == 0 ? 4 :
2,332✔
769
               wordflag == 1 ? 8 :
770
               error("Unknown word size flag in header")
771
    endian_bom = endianflag == 0 ? 0x04030201 :
1,172✔
772
                 endianflag == 1 ? 0x01020304 :
773
                 error("Unknown endianness flag in header")
774
    # Check protocol compatibility.
775
    endian_bom == ENDIAN_BOM  || error("Serialized byte order mismatch ($(repr(endian_bom)))")
1,166✔
776
    # We don't check wordsize == sizeof(Int) here, as Int is encoded concretely
777
    # as Int32 or Int64, which should be enough to correctly deserialize a range
778
    # of data structures between Julia versions.
779
    if version > ser_version
1,160✔
780
        error("""Cannot read stream serialized with a newer version of Julia.
3✔
781
                 Got data version $version > current version $ser_version""")
782
    end
783
    s.version = version
1,157✔
784
    return
1,157✔
785
end
786

787
"""
788
    serialize(stream::IO, value)
789

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

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

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

807
In some cases, the word size (32- or 64-bit) of the reading and writing machines must match.
808
In rarer cases the OS or architecture must also match, for example when using packages
809
that contain platform-dependent code.
810
"""
811
function serialize(s::IO, x)
1,143✔
812
    ss = Serializer(s)
1,143✔
813
    writeheader(ss)
1,143✔
814
    serialize(ss, x)
1,143✔
815
end
816

817
"""
818
    serialize(filename::AbstractString, value)
819

820
Open a file and serialize the given value to it.
821

822
!!! compat "Julia 1.1"
823
    This method is available as of Julia 1.1.
824
"""
825
serialize(filename::AbstractString, x) = open(io->serialize(io, x), filename, "w")
1,474✔
826

827
## deserializing values ##
828

829
"""
830
    deserialize(stream)
831

832
Read a value written by [`serialize`](@ref). `deserialize` assumes the binary data read from
833
`stream` is correct and has been serialized by a compatible implementation of [`serialize`](@ref).
834
`deserialize` is designed for simplicity and performance, and so does not validate
835
the data read. Malformed data can result in process termination. The caller must ensure
836
the integrity and correctness of data read from `stream`.
837
"""
838
deserialize(s::IO) = deserialize(Serializer(s))
1,163✔
839

840
"""
841
    deserialize(filename::AbstractString)
842

843
Open a file and deserialize its contents.
844

845
!!! compat "Julia 1.1"
846
    This method is available as of Julia 1.1.
847
"""
848
deserialize(filename::AbstractString) = open(deserialize, filename)
766✔
849

850
function deserialize(s::AbstractSerializer)
4,354,342✔
851
    handle_deserialize(s, Int32(read(s.io, UInt8)::UInt8))
14,466,709✔
852
end
853

854
function deserialize_cycle(s::AbstractSerializer, @nospecialize(x))
722,901✔
855
    slot = pop!(s.pending_refs)
722,901✔
856
    s.table[slot] = x
722,901✔
857
    nothing
722,901✔
858
end
859

860
# optimized version of:
861
#     slot = s.counter; s.counter += 1
862
#     push!(s.pending_refs, slot)
863
#     slot = pop!(s.pending_refs)
864
#     s.table[slot] = x
865
function resolve_ref_immediately(s::AbstractSerializer, @nospecialize(x))
866
    s.table[s.counter] = x
172,642✔
867
    s.counter += 1
172,642✔
868
    nothing
172,642✔
869
end
870

871
function gettable(s::AbstractSerializer, id::Int)
872
    get(s.table, id) do
5,624,018✔
873
        errmsg = """Inconsistent Serializer state when deserializing.
×
874
            Attempt to access internal table with key $id failed.
875

876
            This might occur if the Serializer contexts when serializing and deserializing are inconsistent.
877
            In particular, if multiple serialize calls use the same Serializer object then
878
            the corresponding deserialize calls should also use the same Serializer object.
879
        """
880
        error(errmsg)
×
881
    end
882
end
883

884
# deserialize_ is an internal function to dispatch on the tag
885
# describing the serialized representation. the number of
886
# representations is fixed, so deserialize_ does not get extended.
887
function handle_deserialize(s::AbstractSerializer, b::Int32)
16,683,822✔
888
    if b == 0
16,683,822✔
889
        return desertag(Int32(read(s.io, UInt8)::UInt8))
76,608✔
890
    end
891
    if b >= VALUE_TAGS
16,607,214✔
892
        return desertag(b)
1,208,337✔
893
    elseif b == TUPLE_TAG
15,398,877✔
894
        return deserialize_tuple(s, Int(read(s.io, UInt8)::UInt8))
48,096✔
895
    elseif b == SHORTBACKREF_TAG
15,350,781✔
896
        id = read(s.io, UInt16)::UInt16
5,624,015✔
897
        return gettable(s, Int(id))
5,624,015✔
898
    elseif b == BACKREF_TAG
9,726,766✔
899
        id = read(s.io, Int32)::Int32
3✔
900
        return gettable(s, Int(id))
3✔
901
    elseif b == ARRAY_TAG
9,726,763✔
902
        return deserialize_array(s)
27,713✔
903
    elseif b == DATATYPE_TAG
9,699,050✔
904
        return deserialize_datatype(s, false)
253,842✔
905
    elseif b == FULL_DATATYPE_TAG
9,445,208✔
906
        return deserialize_datatype(s, true)
1,063✔
907
    elseif b == WRAPPER_DATATYPE_TAG
9,444,145✔
908
        tname = deserialize(s)::Core.TypeName
5,380✔
909
        return unwrap_unionall(tname.wrapper)
5,368✔
910
    elseif b == OBJECT_TAG
9,438,765✔
911
        t = deserialize(s)
720,483✔
912
        if t === Missing
720,471✔
913
            return missing
×
914
        end
915
        return deserialize(s, t)
720,471✔
916
    elseif b == REF_OBJECT_TAG
8,718,282✔
917
        slot = s.counter; s.counter += 1
714,720✔
918
        push!(s.pending_refs, slot)
714,720✔
919
        t = deserialize(s)
714,720✔
920
        return deserialize(s, t)
714,717✔
921
    elseif b == SHARED_REF_TAG
8,003,562✔
922
        slot = s.counter; s.counter += 1
1,066,904✔
923
        obj = deserialize(s)
1,066,904✔
924
        s.table[slot] = obj
1,066,904✔
925
        return obj
1,066,904✔
926
    elseif b == SYMBOL_TAG
6,936,658✔
927
        return deserialize_symbol(s, Int(read(s.io, UInt8)::UInt8))
349,346✔
928
    elseif b == SHORTINT64_TAG
6,587,312✔
929
        return Int64(read(s.io, Int32)::Int32)
55,394✔
930
    elseif b == EXPR_TAG
6,531,918✔
931
        return deserialize_expr(s, Int(read(s.io, UInt8)::UInt8))
12,207✔
932
    elseif b == MODULE_TAG
6,519,711✔
933
        return deserialize_module(s)
261,149✔
934
    elseif b == STRING_TAG
6,258,562✔
935
        return deserialize_string(s, Int(read(s.io, UInt8)::UInt8))
5,338,624✔
936
    elseif b == LONGSTRING_TAG
919,938✔
937
        return deserialize_string(s, Int(read(s.io, Int64)::Int64))
20,180✔
938
    elseif b == SIMPLEVECTOR_TAG
899,758✔
939
        return deserialize_svec(s)
6,580✔
940
    elseif b == GLOBALREF_TAG
893,178✔
941
        return GlobalRef(deserialize(s)::Module, deserialize(s)::Symbol)
5,112✔
942
    elseif b == FULL_GLOBALREF_TAG
888,066✔
943
        ty = deserialize(s)
42✔
944
        tn = unwrap_unionall(ty).name
42✔
945
        return GlobalRef(tn.module, tn.name)
42✔
946
    elseif b == LONGTUPLE_TAG
888,024✔
947
        return deserialize_tuple(s, Int(read(s.io, Int32)::Int32))
3✔
948
    elseif b == LONGEXPR_TAG
888,021✔
949
        return deserialize_expr(s, Int(read(s.io, Int32)::Int32))
3✔
950
    elseif b == LONGBACKREF_TAG
888,018✔
951
        id = read(s.io, Int64)::Int64
×
952
        return gettable(s, Int(id))
×
953
    elseif b == LONGSYMBOL_TAG
888,018✔
954
        return deserialize_symbol(s, Int(read(s.io, Int32)::Int32))
3✔
955
    elseif b == HEADER_TAG
888,015✔
956
        readheader(s)
1,169✔
957
        return deserialize(s)
1,157✔
958
    elseif b == INT8_TAG
886,846✔
959
        return read(s.io, Int8)
60✔
960
    elseif b == INT8_TAG+1
886,786✔
961
        return read(s.io, UInt8)
5,979✔
962
    elseif b == INT8_TAG+2
880,807✔
963
        return read(s.io, Int16)
36✔
964
    elseif b == INT8_TAG+3
880,771✔
965
        return read(s.io, UInt16)
4,017✔
966
    elseif b == INT32_TAG
876,754✔
967
        return read(s.io, Int32)
1,248✔
968
    elseif b == INT8_TAG+5
875,506✔
969
        return read(s.io, UInt32)
226✔
970
    elseif b == INT64_TAG
875,280✔
971
        return read(s.io, Int64)
482✔
972
    elseif b == INT8_TAG+7
874,798✔
973
        return read(s.io, UInt64)
5,255✔
974
    elseif b == INT8_TAG+8
869,543✔
975
        return read(s.io, Int128)
33,222✔
976
    elseif b == INT8_TAG+9
836,321✔
977
        return read(s.io, UInt128)
578,240✔
978
    elseif b == INT8_TAG+10
258,081✔
979
        return read(s.io, Float16)
12✔
980
    elseif b == INT8_TAG+11
258,069✔
981
        return read(s.io, Float32)
×
982
    elseif b == INT8_TAG+12
258,069✔
983
        return read(s.io, Float64)
193,117✔
984
    elseif b == INT8_TAG+13
64,952✔
985
        return read(s.io, Char)
33,411✔
986
    elseif b == IDDICT_TAG
31,541✔
987
        slot = s.counter; s.counter += 1
6✔
988
        push!(s.pending_refs, slot)
6✔
989
        t = deserialize(s)
6✔
990
        return deserialize_dict(s, t)
6✔
991
    end
992
    t = desertag(b)::DataType
31,535✔
993
    if ismutabletype(t) && length(t.types) > 0  # manual specialization of fieldcount
31,535✔
994
        slot = s.counter; s.counter += 1
8,264✔
995
        push!(s.pending_refs, slot)
8,264✔
996
    end
997
    return deserialize(s, t)
31,535✔
998
end
999

1000
function deserialize_symbol(s::AbstractSerializer, len::Int)
349,349✔
1001
    str = Base._string_n(len)
349,349✔
1002
    unsafe_read(s.io, pointer(str), len)
349,349✔
1003
    sym = Symbol(str)
349,349✔
1004
    if len > 7
349,349✔
1005
        resolve_ref_immediately(s, sym)
160,432✔
1006
    end
1007
    return sym
349,349✔
1008
end
1009

1010
deserialize_tuple(s::AbstractSerializer, len) = ntupleany(i->deserialize(s), len)
139,921✔
1011

1012
function deserialize_svec(s::AbstractSerializer)
6,580✔
1013
    n = read(s.io, Int32)
6,580✔
1014
    svec(Any[ deserialize(s) for i=1:n ]...)
6,580✔
1015
end
1016

1017
function deserialize_module(s::AbstractSerializer)
261,149✔
1018
    mkey = deserialize(s)
261,149✔
1019
    if isa(mkey, Tuple)
261,149✔
1020
        # old version, TODO: remove
1021
        if mkey === ()
×
1022
            return Main
×
1023
        end
1024
        m = Base.root_module(mkey[1])
×
1025
        for i = 2:length(mkey)
×
1026
            m = getglobal(m, mkey[i])::Module
×
1027
        end
×
1028
    else
1029
        name = String(deserialize(s)::Symbol)
261,149✔
1030
        pkg = (mkey === nothing) ? Base.PkgId(name) : Base.PkgId(Base.UUID(mkey), name)
327,800✔
1031
        m = Base.root_module(pkg)
261,149✔
1032
        mname = deserialize(s)
261,149✔
1033
        while mname !== ()
262,796✔
1034
            m = getglobal(m, mname)::Module
1,653✔
1035
            mname = deserialize(s)
1,647✔
1036
        end
1,647✔
1037
    end
1038
    return m
261,143✔
1039
end
1040

1041
function deserialize(s::AbstractSerializer, ::Type{Method})
1,287✔
1042
    lnumber = read(s.io, UInt64)
1,287✔
1043
    meth = lookup_object_number(s, lnumber)
1,290✔
1044
    if meth !== nothing
1,287✔
1045
        meth = meth::Method
3✔
1046
        makenew = false
3✔
1047
    else
1048
        meth = ccall(:jl_new_method_uninit, Ref{Method}, (Any,), Main)
1,284✔
1049
        makenew = true
1,284✔
1050
    end
1051
    deserialize_cycle(s, meth)
1,287✔
1052
    mod = deserialize(s)::Module
1,287✔
1053
    name = deserialize(s)::Symbol
1,287✔
1054
    file = deserialize(s)::Symbol
1,287✔
1055
    line = deserialize(s)::Int32
1,287✔
1056
    sig = deserialize(s)::Type
1,287✔
1057
    syms = deserialize(s)
1,287✔
1058
    if syms isa SimpleVector
1,287✔
1059
        # < v1.2
1060
        _ambig = deserialize(s)
3✔
1061
    else
1062
        slot_syms = syms::String
1,284✔
1063
    end
1064
    nargs = deserialize(s)::Int32
1,287✔
1065
    isva = deserialize(s)::Bool
1,287✔
1066
    is_for_opaque_closure = false
1,287✔
1067
    nospecializeinfer = false
1,287✔
1068
    constprop = 0x00
1,287✔
1069
    purity = 0x0000
1,287✔
1070
    template_or_is_opaque = with(current_module => mod) do
1,287✔
1071
        deserialize(s)
1,287✔
1072
    end
1073
    template = if isa(template_or_is_opaque, Bool)
1,287✔
1074
        is_for_opaque_closure = template_or_is_opaque
1,284✔
1075
        if format_version(s) >= 24
1,284✔
1076
            nospecializeinfer = deserialize(s)::Bool
1,284✔
1077
        end
1078
        if format_version(s) >= 14
1,284✔
1079
            constprop = deserialize(s)::UInt8
1,284✔
1080
        end
1081
        if format_version(s) >= 26
1,284✔
1082
            purity = deserialize(s)::UInt16
1,284✔
1083
        elseif format_version(s) >= 17
×
1084
            purity = UInt16(deserialize(s)::UInt8)
×
1085
        end
1086
        with(current_module => mod) do
1,284✔
1087
            deserialize(s)
1,284✔
1088
        end
1089
    else
1090
        template_or_is_opaque
1,290✔
1091
    end
1092
    generator = deserialize(s)
1,287✔
1093
    recursion_relation = nothing
1,287✔
1094
    if format_version(s) >= 15
1,287✔
1095
        recursion_relation = deserialize(s)
1,284✔
1096
    end
1097
    if makenew
1,287✔
1098
        meth.module = mod
1,284✔
1099
        meth.debuginfo = NullDebugInfo
1,284✔
1100
        meth.name = name
1,284✔
1101
        meth.file = file
1,284✔
1102
        meth.line = line
1,284✔
1103
        meth.sig = sig
1,284✔
1104
        meth.nargs = nargs
1,284✔
1105
        meth.isva = isva
1,284✔
1106
        meth.is_for_opaque_closure = is_for_opaque_closure
1,284✔
1107
        meth.nospecializeinfer = nospecializeinfer
1,284✔
1108
        meth.constprop = constprop
1,284✔
1109
        meth.purity = purity
1,284✔
1110
        if template !== nothing
1,284✔
1111
            # TODO: compress template
1112
            template = template::CodeInfo
1,284✔
1113
            if format_version(s) < 29
1,284✔
1114
                template.nargs = nargs
3✔
1115
                template.isva = isva
3✔
1116
            end
1117
            meth.source = template
1,284✔
1118
            meth.debuginfo = template.debuginfo
1,284✔
1119
            if !@isdefined(slot_syms)
1,284✔
1120
                slot_syms = ccall(:jl_compress_argnames, Ref{String}, (Any,), meth.source.slotnames)
3✔
1121
            end
1122
        end
1123
        meth.slot_syms = slot_syms
1,284✔
1124
        if generator !== nothing
1,284✔
1125
            meth.generator = generator
×
1126
        end
1127
        if recursion_relation !== nothing
1,284✔
1128
            meth.recursion_relation = recursion_relation
×
1129
        end
1130
        if !is_for_opaque_closure
1,284✔
1131
            mt = Core.methodtable
1,284✔
1132
            if nothing === ccall(:jl_methtable_lookup, Any, (Any, UInt), sig, Base.get_world_counter()) # XXX: quite sketchy?
1,284✔
1133
                ccall(:jl_method_table_insert, Cvoid, (Any, Any, Ptr{Cvoid}), mt, meth, C_NULL)
1,281✔
1134
            end
1135
        end
1136
        remember_object(s, meth, lnumber)
1,284✔
1137
    end
1138
    return meth
1,287✔
1139
end
1140

1141
function deserialize(s::AbstractSerializer, ::Type{Core.MethodTable})
×
1142
    name = deserialize(s)::Symbol
×
1143
    mod = deserialize(s)::Module
×
1144
    return getglobal(mod, name)::Core.MethodTable
×
1145
end
1146

1147
function deserialize(s::AbstractSerializer, ::Type{Core.MethodInstance})
×
1148
    linfo = ccall(:jl_new_method_instance_uninit, Ref{Core.MethodInstance}, (Ptr{Cvoid},), C_NULL)
×
1149
    deserialize_cycle(s, linfo)
×
1150
    if format_version(s) < 28
×
1151
        tag = Int32(read(s.io, UInt8)::UInt8)
×
1152
        if tag != UNDEFREF_TAG
×
1153
            code = handle_deserialize(s, tag)::CodeInfo
×
1154
            ci = ccall(:jl_new_codeinst_for_uninferred, Ref{CodeInstance}, (Any, Any), linfo, code)
×
1155
            @atomic linfo.cache = ci
×
1156
        end
1157
    end
1158
    tag = Int32(read(s.io, UInt8)::UInt8)
×
1159
    if tag != UNDEFREF_TAG
×
1160
        # for reading files prior to v1.2
1161
        handle_deserialize(s, tag)
×
1162
    end
1163
    linfo.sparam_vals = deserialize(s)::SimpleVector
×
1164
    _rettype = deserialize(s)  # for backwards compat
×
1165
    linfo.specTypes = deserialize(s)
×
1166
    linfo.def = deserialize(s)
×
1167
    return linfo
×
1168
end
1169

1170
function deserialize(s::AbstractSerializer, ::Type{Core.LineInfoNode})
12✔
1171
    mod = deserialize(s)
12✔
1172
    if mod isa Module
12✔
1173
        method = deserialize(s)
12✔
1174
    else
1175
        # files post v1.2 and pre v1.6 are broken
1176
        method = mod
×
1177
        mod = Main
×
1178
    end
1179
    return Core.LineInfoNode(mod, method, deserialize(s)::Symbol, Int32(deserialize(s)::Union{Int32, Int}), Int32(deserialize(s)::Union{Int32, Int}))
12✔
1180
end
1181

1182

1183
function deserialize(s::AbstractSerializer, ::Type{PhiNode})
×
1184
    edges = deserialize(s)
×
1185
    if edges isa Vector{Any}
×
1186
        edges = Vector{Int32}(edges)
×
1187
    end
1188
    values = deserialize(s)::Vector{Any}
×
1189
    return PhiNode(edges, values)
×
1190
end
1191

1192
# v1.12 disallows bare symbols in IR, but older CodeInfos might still have them
1193
function symbol_to_globalref(@nospecialize(x), m::Module)
26,693✔
1194
    mapper(@nospecialize(x)) = symbol_to_globalref(x, m)
42,413✔
1195
    if x isa Symbol
26,693✔
1196
        return GlobalRef(m, x)
15✔
1197
    elseif x isa Expr
26,678✔
1198
        return Expr(x.head, map(mapper, x.args)...)
5,467✔
1199
    elseif x isa ReturnNode
21,211✔
1200
        return ReturnNode(mapper(x.val))
1,384✔
1201
    elseif x isa GotoIfNot
19,827✔
1202
        return GotoIfNot(mapper(x.cond), x.dest)
571✔
1203
    else
1204
        return x
19,256✔
1205
    end
1206
end
1207

1208
function deserialize(s::AbstractSerializer, ::Type{CodeInfo})
1,296✔
1209
    ci = ccall(:jl_new_code_info_uninit, Ref{CodeInfo}, ())
1,296✔
1210
    deserialize_cycle(s, ci)
1,296✔
1211
    code = deserialize(s)::Vector{Any}
1,296✔
1212
    ci.code = code
1,296✔
1213
    ci.debuginfo = NullDebugInfo
1,296✔
1214
    # allow older-style IR with return and gotoifnot Exprs
1215
    for i in 1:length(code)
1,499✔
1216
        stmt = code[i]
10,973✔
1217
        if isa(stmt, Expr)
10,973✔
1218
            ex = stmt::Expr
4,795✔
1219
            if ex.head === :return
4,795✔
1220
                code[i] = ReturnNode(isempty(ex.args) ? nothing : ex.args[1])
3✔
1221
            elseif ex.head === :gotoifnot
4,792✔
1222
                code[i] = GotoIfNot(ex.args[1], ex.args[2])
×
1223
            end
1224
        end
1225
    end
20,650✔
1226
    if current_module[] !== nothing
2,592✔
1227
        map!(x->symbol_to_globalref(x, current_module[]), code)
12,269✔
1228
    end
1229
    _x = deserialize(s)
1,296✔
1230
    have_debuginfo = _x isa Core.DebugInfo
1,296✔
1231
    if have_debuginfo
1,296✔
1232
        ci.debuginfo = _x
1,284✔
1233
    else
1234
        codelocs = _x::Vector{Int32}
12✔
1235
        # TODO: convert codelocs to debuginfo format?
1236
    end
1237
    _x = deserialize(s)
1,296✔
1238
    if _x isa Array || _x isa Int
2,592✔
1239
        pre_12 = false
1,293✔
1240
    else
1241
        pre_12 = true
3✔
1242
        # < v1.2
1243
        ci.method_for_inference_limit_heuristics = _x
3✔
1244
        _x = deserialize(s)
3✔
1245
    end
1246
    ci.ssavaluetypes = _x
1,296✔
1247
    if pre_12
1,296✔
1248
        linetable = deserialize(s)
3✔
1249
        # TODO: convert linetable to debuginfo format?
1250
    end
1251
    ssaflags = deserialize(s)
1,296✔
1252
    if length(ssaflags) ≠ length(code)
1,296✔
1253
        # make sure the length of `ssaflags` matches that of `code`
1254
        # so that the latest inference doesn't throw on IRs serialized from old versions
1255
        ssaflags = UInt32[0x00 for _ in 1:length(code)]
9✔
1256
    elseif eltype(ssaflags) != UInt32
1,293✔
1257
        ssaflags = map(UInt32, ssaflags)
×
1258
    end
1259
    ci.ssaflags = ssaflags
1,296✔
1260
    if pre_12
1,296✔
1261
        ci.slotflags = deserialize(s)
3✔
1262
    else
1263
        if format_version(s) <= 26
1,293✔
1264
            ci.method_for_inference_limit_heuristics = deserialize(s)
9✔
1265
        end
1266
        if !have_debuginfo # pre v1.11 format
1,293✔
1267
            linetable = deserialize(s)
9✔
1268
            # TODO: convert linetable to debuginfo format?
1269
        end
1270
    end
1271
    ci.slotnames = deserialize(s)
1,296✔
1272
    if !pre_12
1,296✔
1273
        ci.slotflags = deserialize(s)
1,293✔
1274
        ci.slottypes = deserialize(s)
1,293✔
1275
        ci.rettype = deserialize(s)
1,293✔
1276
        ci.parent = deserialize(s)
1,293✔
1277
        if format_version(s) < 29 && ci.parent isa MethodInstance && ci.parent.def isa Method
1,293✔
1278
            ci.nargs = ci.parent.def.nargs
×
1279
        end
1280
        world_or_edges = deserialize(s)
1,293✔
1281
        pre_13 = isa(world_or_edges, Union{UInt, Int})
1,293✔
1282
        if pre_13
1,293✔
1283
            ci.min_world = reinterpret(UInt, world_or_edges)
×
1284
            ci.max_world = reinterpret(UInt, deserialize(s))
×
1285
        else
1286
            ci.edges = world_or_edges
1,293✔
1287
            ci.min_world = deserialize(s)::UInt
1,293✔
1288
            ci.max_world = deserialize(s)::UInt
1,293✔
1289
        end
1290
        if format_version(s) >= 29
1,293✔
1291
            ci.method_for_inference_limit_heuristics = deserialize(s)
1,284✔
1292
        end
1293
    end
1294
    if format_version(s) <= 26
1,296✔
1295
        deserialize(s)::Bool # inferred
12✔
1296
    end
1297
    if format_version(s) < 22
1,296✔
1298
        inlining_cost = deserialize(s)
3✔
1299
        if isa(inlining_cost, Bool)
3✔
1300
            Core.Compiler.set_inlineable!(ci, inlining_cost)
3✔
1301
        else
1302
            ci.inlining_cost = inlining_cost
×
1303
        end
1304
    end
1305
    if format_version(s) >= 29
1,296✔
1306
        ci.nargs = deserialize(s)
1,284✔
1307
    end
1308
    ci.propagate_inbounds = deserialize(s)
1,296✔
1309
    if format_version(s) < 23
1,296✔
1310
        deserialize(s) # `pure` field has been removed
3✔
1311
    end
1312
    if format_version(s) >= 20
1,296✔
1313
        ci.has_fcall = deserialize(s)
1,293✔
1314
    end
1315
    if format_version(s) >= 30
1,296✔
1316
        ci.has_image_globalref = deserialize(s)::Bool
1,284✔
1317
    end
1318
    if format_version(s) >= 24
1,296✔
1319
        ci.nospecializeinfer = deserialize(s)::Bool
1,293✔
1320
    end
1321
    if format_version(s) >= 29
1,296✔
1322
        ci.isva = deserialize(s)::Bool
1,284✔
1323
    end
1324
    if format_version(s) >= 21
1,296✔
1325
        ci.inlining = deserialize(s)::UInt8
1,293✔
1326
    end
1327
    if format_version(s) >= 14
1,296✔
1328
        ci.constprop = deserialize(s)::UInt8
1,293✔
1329
    end
1330
    if format_version(s) >= 26
1,296✔
1331
        ci.purity = deserialize(s)::UInt16
1,293✔
1332
    elseif format_version(s) >= 17
3✔
1333
        ci.purity = deserialize(s)::UInt8
×
1334
    end
1335
    if format_version(s) >= 22
1,296✔
1336
        ci.inlining_cost = deserialize(s)::UInt16
1,293✔
1337
    end
1338
    ci.debuginfo = NullDebugInfo
1,296✔
1339
    return ci
1,296✔
1340
end
1341

1342
import Core: NullDebugInfo
1343

1344
if Int === Int64
1345
const OtherInt = Int32
1346
else
1347
const OtherInt = Int64
1348
end
1349

1350
function deserialize_array(s::AbstractSerializer)
27,713✔
1351
    slot = s.counter; s.counter += 1
27,713✔
1352
    d1 = deserialize(s)
27,713✔
1353
    if isa(d1, Type)
27,713✔
1354
        elty = d1
26,399✔
1355
        d1 = deserialize(s)
26,399✔
1356
    else
1357
        elty = UInt8
1,314✔
1358
    end
1359
    if isa(d1, Int32) || isa(d1, Int64)
55,426✔
1360
        if elty !== Bool && isbitstype(elty)
27,521✔
1361
            a = Vector{elty}(undef, d1)
7,895✔
1362
            s.table[slot] = a
7,895✔
1363
            return read!(s.io, a)
7,895✔
1364
        end
1365
        dims = (Int(d1),)
39,252✔
1366
    elseif d1 isa Dims
192✔
1367
        dims = d1::Dims
192✔
1368
    else
1369
        dims = convert(Dims, d1::Tuple{Vararg{OtherInt}})::Dims
×
1370
    end
1371
    if isbitstype(elty)
19,818✔
1372
        n = prod(dims)::Int
312✔
1373
        if elty === Bool && n > 0
156✔
1374
            A = Array{Bool, length(dims)}(undef, dims)
3✔
1375
            i = 1
3✔
1376
            while i <= n
18✔
1377
                b = read(s.io, UInt8)::UInt8
15✔
1378
                v = (b >> 7) != 0
15✔
1379
                count = b & 0x7f
15✔
1380
                nxt = i + count
15✔
1381
                while i < nxt
42✔
1382
                    A[i] = v
27✔
1383
                    i += 1
27✔
1384
                end
27✔
1385
            end
15✔
1386
        else
1387
            A = read!(s.io, Array{elty}(undef, dims))
153✔
1388
        end
1389
        s.table[slot] = A
156✔
1390
        return A
156✔
1391
    end
1392
    A = Array{elty, length(dims)}(undef, dims)
19,662✔
1393
    s.table[slot] = A
19,662✔
1394
    sizehint!(s.table, s.counter + div(length(A)::Int,4))
20,447✔
1395
    deserialize_fillarray!(A, s)
19,662✔
1396
    return A
19,662✔
1397
end
1398

1399
function deserialize_fillarray!(A::Union{Array{T},Memory{T}}, s::AbstractSerializer) where {T}
19,662✔
1400
    for i = eachindex(A)
26,505✔
1401
        tag = Int32(read(s.io, UInt8)::UInt8)
1,299,474✔
1402
        if tag != UNDEFREF_TAG
1,299,474✔
1403
            @inbounds A[i] = handle_deserialize(s, tag)
1,299,468✔
1404
        end
1405
    end
2,586,046✔
1406
    return A
19,662✔
1407
end
1408

1409
function deserialize(s::AbstractSerializer, X::Type{Memory{T}} where T)
74✔
1410
    slot = pop!(s.pending_refs) # e.g. deserialize_cycle
74✔
1411
    n = deserialize(s)::Int
74✔
1412
    elty = eltype(X)
74✔
1413
    if isbitstype(elty)
74✔
1414
        A = X(undef, n)
74✔
1415
        if X === Memory{Bool}
74✔
1416
            i = 1
×
1417
            while i <= n
×
1418
                b = read(s.io, UInt8)::UInt8
×
1419
                v = (b >> 7) != 0
×
1420
                count = b & 0x7f
×
1421
                nxt = i + count
×
1422
                while i < nxt
×
1423
                    A[i] = v
×
1424
                    i += 1
×
1425
                end
×
1426
            end
×
1427
        else
1428
            A = read!(s.io, A)::X
74✔
1429
        end
1430
        s.table[slot] = A
74✔
1431
        return A
74✔
1432
    end
1433
    A = X(undef, n)
×
1434
    s.table[slot] = A
×
1435
    sizehint!(s.table, s.counter + div(n, 4))
×
1436
    deserialize_fillarray!(A, s)
×
1437
    return A
×
1438
end
1439

1440
function deserialize(s::AbstractSerializer, X::Type{MemoryRef{T}} where T)
×
1441
    x = Core.memoryref(deserialize(s))::X
×
1442
    i = deserialize(s)::Int
×
1443
    i == 2 || (x = Core.memoryref(x, i, true))
×
1444
    return x::X
×
1445
end
1446

1447
function deserialize(s::AbstractSerializer, X::Type{Core.AddrSpace{M}} where M)
68✔
1448
    Core.bitcast(X, read(s.io, UInt8))
68✔
1449
end
1450

1451
function deserialize_expr(s::AbstractSerializer, len)
12,210✔
1452
    e = Expr(:temp)
12,210✔
1453
    resolve_ref_immediately(s, e)
12,210✔
1454
    e.head = deserialize(s)::Symbol
12,210✔
1455
    e.args = Any[ deserialize(s) for i = 1:len ]
28,889✔
1456
    e
12,210✔
1457
end
1458

1459
module __deserialized_types__ end
1460

1461
function deserialize(s::AbstractSerializer, ::Type{Core.TypeName})
27✔
1462
    number = read(s.io, UInt64)
27✔
1463
    return deserialize_typename(s, number)
27✔
1464
end
1465

1466
function deserialize_typename(s::AbstractSerializer, number)
1,284✔
1467
    name = deserialize(s)::Symbol
1,284✔
1468
    tn = lookup_object_number(s, number)
1,290✔
1469
    if tn !== nothing
1,284✔
1470
        makenew = false
6✔
1471
    else
1472
        # reuse the same name for the type, if possible, for nicer debugging
1473
        tn_name = isdefined(__deserialized_types__, name) ? gensym() : name
1,278✔
1474
        tn = ccall(:jl_new_typename_in, Any, (Any, Any, Cint, Cint),
1,278✔
1475
                   tn_name, __deserialized_types__, false, false)
1476
        makenew = true
1,278✔
1477
    end
1478
    tn = tn::Core.TypeName
1,284✔
1479
    remember_object(s, tn, number)
1,284✔
1480
    deserialize_cycle(s, tn)
1,284✔
1481

1482
    names = deserialize(s)::SimpleVector
1,284✔
1483
    super = deserialize(s)::Type
1,284✔
1484
    parameters = deserialize(s)::SimpleVector
1,284✔
1485
    types = deserialize(s)::SimpleVector
1,284✔
1486
    attrs = Core.svec()
1,284✔
1487
    has_instance = deserialize(s)::Bool
1,284✔
1488
    abstr = deserialize(s)::Bool
1,284✔
1489
    mutabl = deserialize(s)::Bool
1,284✔
1490
    ninitialized = deserialize(s)::Int32
1,284✔
1491
    maxm = format_version(s) >= 18 ? deserialize(s)::UInt8 : UInt8(0)
1,284✔
1492

1493
    if makenew
1,284✔
1494
        # TODO: there's an unhanded cycle in the dependency graph at this point:
1495
        # while deserializing super and/or types, we may have encountered
1496
        # tn.wrapper and throw UndefRefException before we get to this point
1497
        ndt = ccall(:jl_new_datatype, Any, (Any, Any, Any, Any, Any, Any, Any, Cint, Cint, Cint),
1,278✔
1498
                    tn, tn.module, super, parameters, names, types, attrs,
1499
                    abstr, mutabl, ninitialized)
1500
        @assert tn == ndt.name
1,278✔
1501
        ccall(:jl_set_const, Cvoid, (Any, Any, Any), tn.module, tn.name, tn.wrapper)
1,278✔
1502
        ty = tn.wrapper
1,278✔
1503
        tn.max_methods = maxm
1,278✔
1504
        if has_instance
1,278✔
1505
            ty = ty::DataType
1,015✔
1506
            if !isdefined(ty, :instance)
1,015✔
1507
                singleton = ccall(:jl_new_struct, Any, (Any, Any...), ty)
×
1508
                # use setfield! directly to avoid `fieldtype` lowering expecting to see a Singleton object already on ty
1509
                ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), ty, Base.fieldindex(DataType, :instance)-1, singleton)
×
1510
            end
1511
        end
1512
    end
1513

1514
    tag = Int32(read(s.io, UInt8)::UInt8)
1,284✔
1515
    if tag != UNDEFREF_TAG
1,284✔
1516
        mtname = handle_deserialize(s, tag)
1,284✔
1517
        defs = deserialize(s)
1,284✔
1518
        maxa = deserialize(s)::Union{Int,Int32}
1,284✔
1519
        if makenew
1,284✔
1520
            tn.singletonname = mtname
1,278✔
1521
            setfield!(tn, :max_args, Int32(maxa), :monotonic)
1,281✔
1522
        end
1523
        tag = Int32(read(s.io, UInt8)::UInt8)
1,284✔
1524
        if tag != UNDEFREF_TAG
1,284✔
1525
            kws = handle_deserialize(s, tag)
3✔
1526
            if makenew && !(kws isa Vector{Method})
3✔
1527
                # old object format -- try to forward from old to new
1528
                @eval Core.kwcall(kwargs::NamedTuple, f::$ty, args...) = $kws(kwargs, f, args...)
×
1529
            end
1530
        end
1531
    end
1532
    return tn
1,284✔
1533
end
1534

1535
function deserialize_datatype(s::AbstractSerializer, full::Bool)
254,905✔
1536
    slot = s.counter; s.counter += 1
254,905✔
1537
    if full
254,905✔
1538
        tname = deserialize(s)::Core.TypeName
1,063✔
1539
        ty = tname.wrapper
1,063✔
1540
    else
1541
        name = deserialize(s)::Symbol
253,842✔
1542
        mod = deserialize(s)::Module
253,842✔
1543
        ty = getglobal(mod, name)
253,842✔
1544
    end
1545
    if isa(ty,DataType) && isempty(ty.parameters)
254,893✔
1546
        t = ty
121,192✔
1547
    else
1548
        np = Int(read(s.io, Int32)::Int32)
133,701✔
1549
        if np == 0
133,701✔
1550
            t = unwrap_unionall(ty)
12✔
1551
        elseif ty === Tuple
133,689✔
1552
            # note np==0 has its own tag
1553
            if np == 1
4,589✔
1554
                t = Tuple{deserialize(s)}
2,739✔
1555
            elseif np == 2
1,850✔
1556
                t = Tuple{deserialize(s), deserialize(s)}
1,452✔
1557
            elseif np == 3
398✔
1558
                t = Tuple{deserialize(s), deserialize(s), deserialize(s)}
245✔
1559
            elseif np == 4
153✔
1560
                t = Tuple{deserialize(s), deserialize(s), deserialize(s), deserialize(s)}
87✔
1561
            else
1562
                t = Tuple{Any[ deserialize(s) for i=1:np ]...}
66✔
1563
            end
1564
        else
1565
            t = ty
129,100✔
1566
            for i = 1:np
140,242✔
1567
                t = t{deserialize(s)}
346,094✔
1568
            end
346,094✔
1569
        end
1570
    end
1571
    s.table[slot] = t
254,893✔
1572
    return t
254,893✔
1573
end
1574

1575
function deserialize(s::AbstractSerializer, ::Type{UnionAll})
281✔
1576
    form = read(s.io, UInt8)
281✔
1577
    if form == 0
281✔
1578
        var = deserialize(s)
6✔
1579
        body = deserialize(s)
6✔
1580
        return UnionAll(var, body)
6✔
1581
    else
1582
        n = read(s.io, Int16)
275✔
1583
        t = deserialize(s)::DataType
275✔
1584
        w = t.name.wrapper
275✔
1585
        k = 0
275✔
1586
        while isa(w, UnionAll)
714✔
1587
            w = w.body
439✔
1588
            k += 1
439✔
1589
        end
439✔
1590
        w = t.name.wrapper
275✔
1591
        k -= n
275✔
1592
        while k > 0
275✔
1593
            w = w.body
×
1594
            k -= 1
×
1595
        end
×
1596
        return w
275✔
1597
    end
1598
end
1599

1600
function deserialize(s::AbstractSerializer, ::Type{Task})
9✔
1601
    t = Task(()->nothing)
9✔
1602
    deserialize_cycle(s, t)
9✔
1603
    t.code = deserialize(s)
9✔
1604
    t.storage = deserialize(s)
9✔
1605
    state = deserialize(s)
9✔
1606
    if state === :runnable
9✔
1607
        @atomic :release t._state = Base.task_state_runnable
×
1608
    elseif state === :done
9✔
1609
        @atomic :release t._state = Base.task_state_done
3✔
1610
    elseif state === :failed
6✔
1611
        @atomic :release t._state = Base.task_state_failed
6✔
1612
    else
1613
        @assert false
×
1614
    end
1615
    t.result = deserialize(s)
9✔
1616
    exc = deserialize(s)
9✔
1617
    if exc === nothing
9✔
1618
        t._isexception = false
×
1619
    elseif exc isa Bool
9✔
1620
        t._isexception = exc
9✔
1621
    else
1622
        t._isexception = true
×
1623
        t.result = exc
×
1624
    end
1625
    t
9✔
1626
end
1627

1628
function deserialize_string(s::AbstractSerializer, len::Int)
1629
    out = ccall(:jl_alloc_string, Ref{String}, (Csize_t,), len)
5,358,804✔
1630
    unsafe_read(s.io, pointer(out), len)
5,358,804✔
1631
    return out
5,358,804✔
1632
end
1633

1634
# default DataType deserializer
1635
function deserialize(s::AbstractSerializer, t::DataType)
743,019✔
1636
    nf = length(t.types)
743,019✔
1637
    if isprimitivetype(t)
743,019✔
1638
        return read(s.io, t)
245✔
1639
    elseif ismutabletype(t)
742,774✔
1640
        x = ccall(:jl_new_struct_uninit, Any, (Any,), t)
10,942✔
1641
        deserialize_cycle(s, x)
10,942✔
1642
        for i in 1:nf
12,247✔
1643
            tag = Int32(read(s.io, UInt8)::UInt8)
35,734✔
1644
            if tag != UNDEFREF_TAG
35,734✔
1645
                ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), x, i-1, handle_deserialize(s, tag))
34,375✔
1646
            end
1647
        end
60,532✔
1648
        return x
10,942✔
1649
    elseif nf == 0
731,832✔
1650
        return ccall(:jl_new_struct_uninit, Any, (Any,), t)
104,642✔
1651
    else
1652
        na = nf
627,190✔
1653
        vflds = Vector{Any}(undef, nf)
627,190✔
1654
        for i in 1:nf
1,171,639✔
1655
            tag = Int32(read(s.io, UInt8)::UInt8)
774,029✔
1656
            if tag != UNDEFREF_TAG
774,029✔
1657
                f = handle_deserialize(s, tag)
774,017✔
1658
                na >= i && (vflds[i] = f)
774,011✔
1659
            else
1660
                na >= i && (na = i - 1) # rest of tail must be undefined values
12✔
1661
            end
1662
        end
920,862✔
1663
        return ccall(:jl_new_structv, Any, (Any, Ptr{Any}, UInt32), t, vflds, na)
627,184✔
1664
    end
1665
end
1666

1667
function deserialize_dict(s::AbstractSerializer, T::Type{<:AbstractDict})
703,935✔
1668
    n = read(s.io, Int32)
703,935✔
1669
    t = T(); sizehint!(t, n)
1,407,864✔
1670
    deserialize_cycle(s, t)
703,935✔
1671
    for i = 1:n
1,407,845✔
1672
        k = deserialize(s)
4,955,381✔
1673
        v = deserialize(s)
4,955,381✔
1674
        t[k] = v
4,955,381✔
1675
    end
9,206,831✔
1676
    return t
703,935✔
1677
end
1678

1679
function deserialize(s::AbstractSerializer, T::Type{Dict{K,V}}) where {K,V}
703,929✔
1680
    return deserialize_dict(s, T)
703,929✔
1681
end
1682

1683
deserialize(s::AbstractSerializer, ::Type{BigInt}) = parse(BigInt, deserialize(s), base = 62)
3✔
1684

1685
function deserialize(s::AbstractSerializer, t::Type{Regex})
3✔
1686
    pattern = deserialize(s)
3✔
1687
    compile_options = deserialize(s)
3✔
1688
    match_options = deserialize(s)
3✔
1689
    return Regex(pattern, compile_options, match_options)
3✔
1690
end
1691

1692
## StackTraces
1693

1694
# provide a custom serializer that skips attempting to serialize the `outer_linfo`
1695
# which is likely to contain complex references, types, and module references
1696
# that may not exist on the receiver end
1697
function serialize(s::AbstractSerializer, frame::Base.StackTraces.StackFrame)
9,973✔
1698
    serialize_type(s, typeof(frame))
9,973✔
1699
    serialize(s, frame.func)
9,973✔
1700
    serialize(s, frame.file)
9,973✔
1701
    write(s.io, frame.line)
9,973✔
1702
    write(s.io, frame.from_c)
9,978✔
1703
    write(s.io, frame.inlined)
9,978✔
1704
    write(s.io, frame.pointer)
9,973✔
1705
    nothing
9,973✔
1706
end
1707

1708
function deserialize(s::AbstractSerializer, ::Type{Base.StackTraces.StackFrame})
9,973✔
1709
    func = deserialize(s)
9,973✔
1710
    file = deserialize(s)
9,973✔
1711
    line = read(s.io, Int)
9,973✔
1712
    from_c = read(s.io, Bool)
9,973✔
1713
    inlined = read(s.io, Bool)
9,973✔
1714
    pointer = read(s.io, UInt64)
9,973✔
1715
    return Base.StackTraces.StackFrame(func, file, line, nothing, from_c, inlined, pointer)
9,973✔
1716
end
1717

1718
function serialize(s::AbstractSerializer, lock::Base.AbstractLock)
633✔
1719
    # assert_havelock(lock)
1720
    serialize_cycle_header(s, lock)
1,275✔
1721
    nothing
639✔
1722
end
1723

1724
function deserialize(s::AbstractSerializer, ::Type{T}) where T<:Base.AbstractLock
636✔
1725
    lock = T()
636✔
1726
    deserialize_cycle(s, lock)
636✔
1727
    return lock
636✔
1728
end
1729

1730
function serialize(s::AbstractSerializer, cond::Base.GenericCondition)
1731
    serialize_cycle_header(s, cond) && return
12✔
1732
    serialize(s, cond.lock)
9✔
1733
    nothing
6✔
1734
end
1735

1736
function deserialize(s::AbstractSerializer, ::Type{T}) where T<:Base.GenericCondition
6✔
1737
    lock = deserialize(s)
6✔
1738
    cond = T(lock)
6✔
1739
    deserialize_cycle(s, cond)
6✔
1740
    return cond
6✔
1741
end
1742

1743
serialize(s::AbstractSerializer, l::LazyString) =
6✔
1744
    invoke(serialize, Tuple{AbstractSerializer,Any}, s, Base._LazyString((), string(l)))
1745

1746
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

© 2025 Coveralls, Inc