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

JuliaLang / julia / #37773

08 May 2024 07:57AM UTC coverage: 86.275% (-0.5%) from 86.821%
#37773

push

local

web-flow
Stabilize `MulAddMul` strategically (#52439)

Co-authored-by: Ashley Milsted <ashmilsted@gmail.com>

58 of 79 new or added lines in 4 files covered. (73.42%)

1130 existing lines in 37 files now uncovered.

74527 of 86383 relevant lines covered (86.28%)

15994665.82 hits per line

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

86.14
/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
26
    Serializer{I}(io::I) where I<:IO = new(io, 0, IdDict(), Int[], Dict{UInt64,Any}(), ser_version)
211✔
27
end
28

29
Serializer(io::IO) = Serializer{typeof(io)}(io)
211✔
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 = 28 # do not make changes without bumping the version #!
84

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

88
function sertag(@nospecialize(v))
3✔
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)
53,731✔
92
    ptags = convert(Ptr{Ptr{Cvoid}}, pointer(TAGS))
53,731✔
93
    # note: constant ints & reserved slots never returned here
94
    @inbounds for i in 1:(NTAGS-(n_reserved_slots+2*n_int_literals))
3,080,721✔
95
        ptr == unsafe_load(ptags,i) && return i%Int32
5,764,714✔
96
    end
11,440,580✔
97
    return Int32(-1)
18,614✔
98
end
99
desertag(i::Int32) = @inbounds(TAGS[i])
48,069✔
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)
87,581✔
146

147
function write_as_tag(s::IO, tag)
23,330✔
148
    tag < VALUE_TAGS && write(s, UInt8(0))
34,041✔
149
    write(s, UInt8(tag))
33,904✔
150
    nothing
151
end
152

153
# cycle handling
154
function serialize_cycle(s::AbstractSerializer, @nospecialize(x))
12,462✔
155
    offs = get(s.table, x, -1)::Int
12,462✔
156
    if offs != -1
12,462✔
157
        if offs <= typemax(UInt16)
3,989✔
158
            writetag(s.io, SHORTBACKREF_TAG)
4,067✔
159
            write(s.io, UInt16(offs))
3,989✔
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
3,989✔
168
    end
169
    s.table[x] = s.counter
8,473✔
170
    s.counter += 1
8,473✔
171
    return false
8,473✔
172
end
173

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

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

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

190
serialize(s::AbstractSerializer, p::Ptr) = serialize_any(s, oftype(p, C_NULL))
7✔
191

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

194
function serialize(s::AbstractSerializer, t::Tuple)
824✔
195
    l = length(t)
825✔
196
    if l <= NTAGS
825✔
197
        writetag(s.io, TUPLE_TAG)
850✔
198
        write(s.io, UInt8(l))
850✔
199
    else
200
        writetag(s.io, LONGTUPLE_TAG)
2✔
201
        write(s.io, Int32(l))
1✔
202
    end
203
    for x in t
825✔
204
        serialize(s, x)
2,887✔
205
    end
2,448✔
206
end
207

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

216
function serialize(s::AbstractSerializer, x::Symbol)
10,699✔
217
    tag = sertag(x)
1,679,869✔
218
    if tag > 0
10,699✔
219
        return write_as_tag(s.io, tag)
3,033✔
220
    end
221
    pname = unsafe_convert(Ptr{UInt8}, x)
7,666✔
222
    len = Int(ccall(:strlen, Csize_t, (Cstring,), pname))
7,666✔
223
    if len > 7
7,666✔
224
        serialize_cycle(s, x) && return
3,552✔
225
    end
226
    if len <= NTAGS
6,241✔
227
        writetag(s.io, SYMBOL_TAG)
6,492✔
228
        write(s.io, UInt8(len))
6,492✔
229
    else
230
        writetag(s.io, LONGSYMBOL_TAG)
2✔
231
        write(s.io, Int32(len))
1✔
232
    end
233
    unsafe_write(s.io, pname, len)
6,241✔
234
    nothing
235
end
236

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

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

284
function serialize(s::AbstractSerializer, a::SubArray{T,N,A}) where {T,N,A<:Array}
3✔
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:
287
    b = unaliascopy(a)
4✔
288
    serialize_any(s, b)
4✔
289
end
290

291
serialize(s::AbstractSerializer, m::GenericMemory) = error("GenericMemory{:atomic} currently cannot be serialized")
×
292
function serialize(s::AbstractSerializer, m::Memory)
13✔
293
    serialize_cycle_header(s, m) && return
26✔
294
    serialize(s, length(m))
13✔
295
    elty = eltype(m)
13✔
296
    if isbitstype(elty)
13✔
297
        serialize_array_data(s.io, m)
13✔
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,603✔
317
    len = sizeof(ss)
2,603✔
318
    if len > 7
2,603✔
319
        serialize_cycle(s, ss) && return
1,506✔
320
        writetag(s.io, SHARED_REF_TAG)
736✔
321
    end
322
    if len <= NTAGS
1,815✔
323
        writetag(s.io, STRING_TAG)
1,751✔
324
        write(s.io, UInt8(len))
1,751✔
325
    else
326
        writetag(s.io, LONGSTRING_TAG)
96✔
327
        write(s.io, Int64(len))
95✔
328
    end
329
    write(s.io, ss)
1,815✔
330
    nothing
331
end
332

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

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

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

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

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

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

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

387
function serialize_mod_names(s::AbstractSerializer, m::Module)
3,529✔
388
    p = parentmodule(m)
3,529✔
389
    if p === m || m === Base
4,452✔
390
        key = Base.root_module_key(m)
3,475✔
391
        uuid = key.uuid
3,475✔
392
        serialize(s, uuid === nothing ? nothing : uuid.value)
4,951✔
393
        serialize(s, Symbol(key.name))
3,475✔
394
    else
395
        serialize_mod_names(s, p)
54✔
396
        serialize(s, nameof(m))
54✔
397
    end
398
end
399

400
function serialize(s::AbstractSerializer, m::Module)
247✔
401
    writetag(s.io, MODULE_TAG)
3,625✔
402
    serialize_mod_names(s, m)
3,475✔
403
    writetag(s.io, EMPTYTUPLE_TAG)
3,475✔
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)
409
function object_number(s::AbstractSerializer, @nospecialize(l))
410
    global obj_number_salt, object_numbers
16✔
411
    if haskey(object_numbers, l)
16✔
412
        return object_numbers[l]
2✔
413
    end
414
    ln = obj_number_salt[]
14✔
415
    object_numbers[l] = ln
14✔
416
    obj_number_salt[] += 1
14✔
417
    return ln::UInt64
14✔
418
end
419

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

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

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

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

433
function serialize(s::AbstractSerializer, meth::Method)
59✔
434
    serialize_cycle(s, meth) && return
59✔
435
    writetag(s.io, METHOD_TAG)
67✔
436
    write(s.io, object_number(s, meth))
117✔
437
    serialize(s, meth.module)
59✔
438
    serialize(s, meth.name)
59✔
439
    serialize(s, meth.file)
59✔
440
    serialize(s, meth.line)
59✔
441
    serialize(s, meth.sig)
59✔
442
    serialize(s, meth.slot_syms)
59✔
443
    serialize(s, meth.nargs)
59✔
444
    serialize(s, meth.isva)
110✔
445
    serialize(s, meth.is_for_opaque_closure)
110✔
446
    serialize(s, meth.nospecializeinfer)
110✔
447
    serialize(s, meth.constprop)
59✔
448
    serialize(s, meth.purity)
67✔
449
    if isdefined(meth, :source)
59✔
450
        serialize(s, Base._uncompressed_ast(meth))
59✔
451
    else
452
        serialize(s, nothing)
×
453
    end
454
    if isdefined(meth, :generator)
59✔
455
        serialize(s, meth.generator)
×
456
    else
457
        serialize(s, nothing)
59✔
458
    end
459
    if isdefined(meth, :recursion_relation)
59✔
460
        serialize(s, method.recursion_relation)
×
461
    else
462
        serialize(s, nothing)
59✔
463
    end
464
    if isdefined(meth, :external_mt)
59✔
465
        error("cannot serialize Method objects with external method tables")
×
466
    end
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)
×
UNCOV
475
    serialize(s, Any)  # for backwards compat
×
476
    serialize(s, linfo.specTypes)
×
UNCOV
477
    serialize(s, linfo.def)
×
478
    nothing
×
479
end
480

481
function serialize(s::AbstractSerializer, t::Task)
2✔
482
    serialize_cycle(s, t) && return
2✔
483
    if istaskstarted(t) && !istaskdone(t)
2✔
UNCOV
484
        error("cannot serialize a running Task")
×
485
    end
486
    writetag(s.io, TASK_TAG)
4✔
487
    serialize(s, t.code)
2✔
488
    serialize(s, t.storage)
2✔
489
    serialize(s, t.state)
4✔
490
    if t._isexception && (stk = Base.current_exceptions(t); !isempty(stk))
2✔
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.
494
        serialize(s, CapturedException(stk[1].exception, stk[1].backtrace))
1✔
495
    else
496
        serialize(s, t.result)
1✔
497
    end
498
    serialize(s, t._isexception)
2✔
499
end
500

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

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

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

527
function serialize_typename(s::AbstractSerializer, t::Core.TypeName)
59✔
528
    serialize(s, t.name)
59✔
529
    serialize(s, t.names)
59✔
530
    primary = unwrap_unionall(t.wrapper)
59✔
531
    serialize(s, primary.super)
59✔
532
    serialize(s, primary.parameters)
59✔
533
    serialize(s, primary.types)
59✔
534
    serialize(s, Base.issingletontype(primary))
103✔
535
    serialize(s, t.flags & 0x1 == 0x1) # .abstract
110✔
536
    serialize(s, t.flags & 0x2 == 0x2) # .mutable
110✔
537
    serialize(s, Int32(length(primary.types) - t.n_uninitialized))
59✔
538
    serialize(s, t.max_methods)
59✔
539
    if isdefined(t, :mt) && t.mt !== Symbol.name.mt
59✔
540
        serialize(s, t.mt.name)
58✔
541
        serialize(s, collect(Base.MethodList(t.mt)))
116✔
542
        serialize(s, t.mt.max_args)
58✔
543
        kws = collect(methods(Core.kwcall, (Any, t.wrapper, Vararg)))
59✔
544
        if isempty(kws)
58✔
545
            writetag(s.io, UNDEFREF_TAG)
57✔
546
        else
547
            serialize(s, kws)
1✔
548
        end
549
    else
550
        writetag(s.io, UNDEFREF_TAG)
1✔
551
    end
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
5,137✔
558
    if isdefined(tn, :mt)
5,137✔
559
        # TODO improve somehow
560
        # send whole type for anonymous functions in Main
561
        name = tn.mt.name
5,078✔
562
        mod = tn.module
5,078✔
563
        isanonfunction = mod === Main && # only Main
5,079✔
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
10,156✔
571
    end
572
    return false
59✔
573
end
574

575
function serialize_type_data(s, @nospecialize(t::DataType))
5,131✔
576
    whole = should_send_whole_type(s, t)
10,203✔
577
    iswrapper = (t === unwrap_unionall(t.name.wrapper))
5,131✔
578
    if whole && iswrapper
5,131✔
579
        writetag(s.io, WRAPPER_DATATYPE_TAG)
92✔
580
        serialize(s, t.name)
75✔
581
        return
75✔
582
    end
583
    serialize_cycle(s, t) && return
5,056✔
584
    if whole
3,445✔
585
        writetag(s.io, FULL_DATATYPE_TAG)
218✔
586
        serialize(s, t.name)
216✔
587
    else
588
        writetag(s.io, DATATYPE_TAG)
3,358✔
589
        serialize(s, nameof(t))
3,229✔
590
        serialize(s, parentmodule(t))
3,229✔
591
    end
592
    if !isempty(t.parameters)
3,445✔
593
        if iswrapper
1,627✔
594
            write(s.io, Int32(0))
4✔
595
        else
596
            write(s.io, Int32(length(t.parameters)))
1,623✔
597
            for p in t.parameters
3,246✔
598
                serialize(s, p)
4,434✔
599
            end
4,434✔
600
        end
601
    end
602
    nothing
603
end
604

605
function serialize(s::AbstractSerializer, t::DataType)
4,533✔
606
    tag = sertag(t)
350,938✔
607
    tag > 0 && return write_as_tag(s.io, tag)
4,533✔
608
    if t === Tuple
1,303✔
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
UNCOV
613
        return write_as_tag(s.io, TUPLE_TAG)
×
614
    end
615
    serialize_type_data(s, t)
1,303✔
616
end
617

618
function serialize_type(s::AbstractSerializer, @nospecialize(t::DataType), ref::Bool = false)
5,769✔
619
    tag = sertag(t)
686,726✔
620
    tag > 0 && return writetag(s.io, tag)
5,755✔
621
    writetag(s.io, ref ? REF_OBJECT_TAG : OBJECT_TAG)
3,926✔
622
    serialize_type_data(s, t)
3,826✔
623
end
624

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

635
function serialize(s::AbstractSerializer, n::Int64)
7,103✔
636
    if 0 <= n <= (n_int_literals-1)
7,103✔
637
        write(s.io, UInt8(ZERO64_TAG+n))
4,260✔
638
    elseif typemin(Int32) <= n <= typemax(Int32)
2,843✔
639
        writetag(s.io, SHORTINT64_TAG)
2,705✔
640
        write(s.io, Int32(n))
2,700✔
641
    else
642
        writetag(s.io, INT64_TAG)
144✔
643
        write(s.io, n)
143✔
644
    end
645
    nothing
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)
47,242✔
653
end
654

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

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

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

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

682
function serialize_any(s::AbstractSerializer, @nospecialize(x))
32,735✔
683
    tag = sertag(x)
3,065,402✔
684
    if tag > 0
32,735✔
685
        return write_as_tag(s.io, tag)
26,916✔
686
    end
687
    t = typeof(x)::DataType
5,819✔
688
    if isprimitivetype(t)
5,819✔
689
        serialize_type(s, t)
12✔
690
        write(s.io, x)
12✔
691
    else
692
        if ismutable(x)
5,807✔
693
            serialize_cycle(s, x) && return
288✔
694
            serialize_type(s, t, true)
188✔
695
        else
696
            serialize_type(s, t, false)
5,519✔
697
        end
698
        nf = nfields(x)
5,707✔
699
        for i in 1:nf
5,707✔
700
            if isdefined(x, i)
17,115✔
701
                serialize(s, getfield(x, i))
17,114✔
702
            else
703
                writetag(s.io, UNDEFREF_TAG)
1✔
704
            end
705
        end
17,115✔
706
    end
707
    nothing
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
"""
725
function writeheader(s::AbstractSerializer)
111✔
726
    io = s.io
111✔
727
    writetag(io, HEADER_TAG)
206✔
728
    write(io, "JL")  # magic bytes
111✔
729
    write(io, UInt8(ser_version))
206✔
730
    endianness = (ENDIAN_BOM == 0x04030201 ? 0 :
111✔
731
                  ENDIAN_BOM == 0x01020304 ? 1 :
732
                  error("unsupported endianness in serializer"))
733
    machine = (sizeof(Int) == 4 ? 0 :
111✔
734
               sizeof(Int) == 8 ? 1 :
735
               error("unsupported word size in serializer"))
736
    write(io, UInt8(endianness) | (UInt8(machine) << 2))
206✔
737
    write(io, [0x00,0x00,0x00]) # 3 reserved bytes
111✔
738
    nothing
739
end
740

741
function readheader(s::AbstractSerializer)
101✔
742
    # Tag already read
743
    io = s.io
101✔
744
    m1 = read(io, UInt8)
101✔
745
    m2 = read(io, UInt8)
101✔
746
    if m1 != UInt8('J') || m2 != UInt8('L')
202✔
UNCOV
747
        error("Unsupported serialization format (got header magic bytes $m1 $m2)")
×
748
    end
749
    version    = read(io, UInt8)
101✔
750
    flags      = read(io, UInt8)
101✔
751
    reserved1  = read(io, UInt8)
101✔
752
    reserved2  = read(io, UInt8)
101✔
753
    reserved3  = read(io, UInt8)
101✔
754
    endianflag = flags & 0x3
101✔
755
    wordflag   = (flags >> 2) & 0x3
101✔
756
    wordsize = wordflag == 0 ? 4 :
200✔
757
               wordflag == 1 ? 8 :
758
               error("Unknown word size flag in header")
759
    endian_bom = endianflag == 0 ? 0x04030201 :
102✔
760
                 endianflag == 1 ? 0x01020304 :
761
                 error("Unknown endianness flag in header")
762
    # Check protocol compatibility.
763
    endian_bom == ENDIAN_BOM  || error("Serialized byte order mismatch ($(repr(endian_bom)))")
100✔
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.
767
    if version > ser_version
98✔
768
        error("""Cannot read stream serialized with a newer version of Julia.
1✔
769
                 Got data version $version > current version $ser_version""")
770
    end
771
    s.version = version
97✔
772
    return
97✔
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
"""
799
function serialize(s::IO, x)
62✔
800
    ss = Serializer(s)
111✔
801
    writeheader(ss)
111✔
802
    serialize(ss, x)
111✔
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
"""
813
serialize(filename::AbstractString, x) = open(io->serialize(io, x), filename, "w")
2✔
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
"""
826
deserialize(s::IO) = deserialize(Serializer(s))
99✔
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
"""
836
deserialize(filename::AbstractString) = open(deserialize, filename)
1✔
837

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

842
function deserialize_cycle(s::AbstractSerializer, @nospecialize(x))
51✔
843
    slot = pop!(s.pending_refs)
51✔
844
    s.table[slot] = x
51✔
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))
4,771✔
854
    s.table[s.counter] = x
4,771✔
855
    s.counter += 1
4,771✔
856
    nothing
857
end
858

859
function gettable(s::AbstractSerializer, id::Int)
860
    get(s.table, id) do
2,131✔
UNCOV
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
        """
UNCOV
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)
102,222✔
876
    if b == 0
102,222✔
877
        return desertag(Int32(read(s.io, UInt8)::UInt8))
2,795✔
878
    end
879
    if b >= VALUE_TAGS
99,427✔
880
        return desertag(b)
45,070✔
881
    elseif b == TUPLE_TAG
54,357✔
882
        return deserialize_tuple(s, Int(read(s.io, UInt8)::UInt8))
3,100✔
883
    elseif b == SHORTBACKREF_TAG
51,257✔
884
        id = read(s.io, UInt16)::UInt16
2,131✔
885
        return gettable(s, Int(id))
2,131✔
886
    elseif b == BACKREF_TAG
49,126✔
UNCOV
887
        id = read(s.io, Int32)::Int32
×
UNCOV
888
        return gettable(s, Int(id))
×
889
    elseif b == ARRAY_TAG
49,126✔
890
        return deserialize_array(s)
692✔
891
    elseif b == DATATYPE_TAG
48,434✔
892
        return deserialize_datatype(s, false)
5,026✔
893
    elseif b == FULL_DATATYPE_TAG
43,408✔
894
        return deserialize_datatype(s, true)
2✔
895
    elseif b == WRAPPER_DATATYPE_TAG
43,406✔
896
        tname = deserialize(s)::Core.TypeName
19✔
897
        return unwrap_unionall(tname.wrapper)
19✔
898
    elseif b == OBJECT_TAG
43,387✔
899
        t = deserialize(s)
4,552✔
900
        if t === Missing
4,552✔
UNCOV
901
            return missing
×
902
        end
903
        return deserialize(s, t)
4,552✔
904
    elseif b == REF_OBJECT_TAG
38,835✔
905
        slot = s.counter; s.counter += 1
16✔
906
        push!(s.pending_refs, slot)
16✔
907
        t = deserialize(s)
16✔
908
        return deserialize(s, t)
16✔
909
    elseif b == SHARED_REF_TAG
38,819✔
910
        slot = s.counter; s.counter += 1
517✔
911
        obj = deserialize(s)
517✔
912
        s.table[slot] = obj
517✔
913
        return obj
517✔
914
    elseif b == SYMBOL_TAG
38,302✔
915
        return deserialize_symbol(s, Int(read(s.io, UInt8)::UInt8))
6,847✔
916
    elseif b == SHORTINT64_TAG
31,455✔
917
        return Int64(read(s.io, Int32)::Int32)
960✔
918
    elseif b == EXPR_TAG
30,495✔
919
        return deserialize_expr(s, Int(read(s.io, UInt8)::UInt8))
487✔
920
    elseif b == MODULE_TAG
30,008✔
921
        return deserialize_module(s)
5,079✔
922
    elseif b == STRING_TAG
24,929✔
923
        return deserialize_string(s, Int(read(s.io, UInt8)::UInt8))
595✔
924
    elseif b == LONGSTRING_TAG
24,334✔
925
        return deserialize_string(s, Int(read(s.io, Int64)::Int64))
1✔
926
    elseif b == SIMPLEVECTOR_TAG
24,333✔
927
        return deserialize_svec(s)
36✔
928
    elseif b == GLOBALREF_TAG
24,297✔
929
        return GlobalRef(deserialize(s)::Module, deserialize(s)::Symbol)
14✔
930
    elseif b == FULL_GLOBALREF_TAG
24,283✔
931
        ty = deserialize(s)
1✔
932
        tn = unwrap_unionall(ty).name
1✔
933
        return GlobalRef(tn.module, tn.name)
1✔
934
    elseif b == LONGTUPLE_TAG
24,282✔
935
        return deserialize_tuple(s, Int(read(s.io, Int32)::Int32))
1✔
936
    elseif b == LONGEXPR_TAG
24,281✔
937
        return deserialize_expr(s, Int(read(s.io, Int32)::Int32))
1✔
938
    elseif b == LONGBACKREF_TAG
24,280✔
UNCOV
939
        id = read(s.io, Int64)::Int64
×
UNCOV
940
        return gettable(s, Int(id))
×
941
    elseif b == LONGSYMBOL_TAG
24,280✔
942
        return deserialize_symbol(s, Int(read(s.io, Int32)::Int32))
1✔
943
    elseif b == HEADER_TAG
24,279✔
944
        readheader(s)
101✔
945
        return deserialize(s)
97✔
946
    elseif b == INT8_TAG
24,178✔
947
        return read(s.io, Int8)
12✔
948
    elseif b == INT8_TAG+1
24,166✔
949
        return read(s.io, UInt8)
296✔
950
    elseif b == INT8_TAG+2
23,870✔
951
        return read(s.io, Int16)
4✔
952
    elseif b == INT8_TAG+3
23,866✔
953
        return read(s.io, UInt16)
28✔
954
    elseif b == INT32_TAG
23,838✔
955
        return read(s.io, Int32)
8✔
956
    elseif b == INT8_TAG+5
23,830✔
957
        return read(s.io, UInt32)
6✔
958
    elseif b == INT64_TAG
23,824✔
959
        return read(s.io, Int64)
1✔
960
    elseif b == INT8_TAG+7
23,823✔
961
        return read(s.io, UInt64)
20✔
962
    elseif b == INT8_TAG+8
23,803✔
963
        return read(s.io, Int128)
11,074✔
964
    elseif b == INT8_TAG+9
12,729✔
965
        return read(s.io, UInt128)
1,416✔
966
    elseif b == INT8_TAG+10
11,313✔
967
        return read(s.io, Float16)
4✔
968
    elseif b == INT8_TAG+11
11,309✔
UNCOV
969
        return read(s.io, Float32)
×
970
    elseif b == INT8_TAG+12
11,309✔
UNCOV
971
        return read(s.io, Float64)
×
972
    elseif b == INT8_TAG+13
11,309✔
973
        return read(s.io, Char)
11,103✔
974
    elseif b == IDDICT_TAG
206✔
975
        slot = s.counter; s.counter += 1
2✔
976
        push!(s.pending_refs, slot)
2✔
977
        t = deserialize(s)
2✔
978
        return deserialize_dict(s, t)
2✔
979
    end
980
    t = desertag(b)::DataType
204✔
981
    if ismutabletype(t) && length(t.types) > 0  # manual specialization of fieldcount
204✔
982
        slot = s.counter; s.counter += 1
33✔
983
        push!(s.pending_refs, slot)
33✔
984
    end
985
    return deserialize(s, t)
204✔
986
end
987

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

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

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

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

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

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

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

1156

UNCOV
1157
function deserialize(s::AbstractSerializer, ::Type{PhiNode})
×
1158
    edges = deserialize(s)
×
1159
    if edges isa Vector{Any}
×
1160
        edges = Vector{Int32}(edges)
×
1161
    end
UNCOV
1162
    values = deserialize(s)::Vector{Any}
×
1163
    return PhiNode(edges, values)
×
1164
end
1165

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

1290
import Core: NullDebugInfo
1291

1292
if Int === Int64
1293
const OtherInt = Int32
1294
else
1295
const OtherInt = Int64
1296
end
1297

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

1347
function deserialize_fillarray!(A::Union{Array{T},Memory{T}}, s::AbstractSerializer) where {T}
123✔
1348
    for i = eachindex(A)
123✔
1349
        tag = Int32(read(s.io, UInt8)::UInt8)
45,159✔
1350
        if tag != UNDEFREF_TAG
45,159✔
1351
            @inbounds A[i] = handle_deserialize(s, tag)
45,157✔
1352
        end
1353
    end
90,198✔
1354
    return A
123✔
1355
end
1356

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

UNCOV
1388
function deserialize(s::AbstractSerializer, X::Type{MemoryRef{T}} where T)
×
1389
    x = Core.memoryref(deserialize(s))::X
×
1390
    i = deserialize(s)::Int
×
1391
    i == 2 || (x = Core.memoryref(x, i, true))
×
1392
    return x::X
×
1393
end
1394

UNCOV
1395
function deserialize(s::AbstractSerializer, X::Type{Core.AddrSpace{M}} where M)
×
1396
    Core.bitcast(X, read(s.io, UInt8))
×
1397
end
1398

1399
function deserialize_expr(s::AbstractSerializer, len)
488✔
1400
    e = Expr(:temp)
488✔
1401
    resolve_ref_immediately(s, e)
488✔
1402
    e.head = deserialize(s)::Symbol
488✔
1403
    e.args = Any[ deserialize(s) for i = 1:len ]
1,254✔
1404
    e
488✔
1405
end
1406

1407
module __deserialized_types__ end
1408

1409
function deserialize(s::AbstractSerializer, ::Type{Core.TypeName})
9✔
1410
    number = read(s.io, UInt64)
9✔
1411
    return deserialize_typename(s, number)
9✔
1412
end
1413

1414
function deserialize_typename(s::AbstractSerializer, number)
9✔
1415
    name = deserialize(s)::Symbol
9✔
1416
    tn = lookup_object_number(s, number)
10✔
1417
    if tn !== nothing
9✔
1418
        makenew = false
1✔
1419
    else
1420
        # reuse the same name for the type, if possible, for nicer debugging
1421
        tn_name = isdefined(__deserialized_types__, name) ? gensym() : name
8✔
1422
        tn = ccall(:jl_new_typename_in, Any, (Any, Any, Cint, Cint),
8✔
1423
                   tn_name, __deserialized_types__, false, false)
1424
        makenew = true
8✔
1425
    end
1426
    tn = tn::Core.TypeName
9✔
1427
    remember_object(s, tn, number)
9✔
1428
    deserialize_cycle(s, tn)
9✔
1429

1430
    names = deserialize(s)::SimpleVector
9✔
1431
    super = deserialize(s)::Type
9✔
1432
    parameters = deserialize(s)::SimpleVector
9✔
1433
    types = deserialize(s)::SimpleVector
9✔
1434
    attrs = Core.svec()
9✔
1435
    has_instance = deserialize(s)::Bool
9✔
1436
    abstr = deserialize(s)::Bool
9✔
1437
    mutabl = deserialize(s)::Bool
9✔
1438
    ninitialized = deserialize(s)::Int32
9✔
1439
    maxm = format_version(s) >= 18 ? deserialize(s)::UInt8 : UInt8(0)
9✔
1440

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

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

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

1536
function deserialize(s::AbstractSerializer, ::Type{UnionAll})
11✔
1537
    form = read(s.io, UInt8)
11✔
1538
    if form == 0
11✔
1539
        var = deserialize(s)
2✔
1540
        body = deserialize(s)
2✔
1541
        return UnionAll(var, body)
2✔
1542
    else
1543
        n = read(s.io, Int16)
9✔
1544
        t = deserialize(s)::DataType
9✔
1545
        w = t.name.wrapper
9✔
1546
        k = 0
9✔
1547
        while isa(w, UnionAll)
19✔
1548
            w = w.body
10✔
1549
            k += 1
10✔
1550
        end
10✔
1551
        w = t.name.wrapper
9✔
1552
        k -= n
9✔
1553
        while k > 0
9✔
UNCOV
1554
            w = w.body
×
1555
            k -= 1
×
1556
        end
×
1557
        return w
9✔
1558
    end
1559
end
1560

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

1589
function deserialize_string(s::AbstractSerializer, len::Int)
1590
    out = ccall(:jl_alloc_string, Ref{String}, (Csize_t,), len)
596✔
1591
    unsafe_read(s.io, pointer(out), len)
596✔
1592
    return out
596✔
1593
end
1594

1595
# default DataType deserializer
1596
function deserialize(s::AbstractSerializer, t::DataType)
4,723✔
1597
    nf = length(t.types)
4,723✔
1598
    if isprimitivetype(t)
4,723✔
1599
        return read(s.io, t)
12✔
1600
    elseif ismutabletype(t)
4,711✔
1601
        x = ccall(:jl_new_struct_uninit, Any, (Any,), t)
15✔
1602
        deserialize_cycle(s, x)
15✔
1603
        for i in 1:nf
15✔
1604
            tag = Int32(read(s.io, UInt8)::UInt8)
30✔
1605
            if tag != UNDEFREF_TAG
30✔
1606
                ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), x, i-1, handle_deserialize(s, tag))
30✔
1607
            end
1608
        end
47✔
1609
        return x
15✔
1610
    elseif nf == 0
4,696✔
1611
        return ccall(:jl_new_struct_uninit, Any, (Any,), t)
2,762✔
1612
    else
1613
        na = nf
1,934✔
1614
        vflds = Vector{Any}(undef, nf)
3,868✔
1615
        for i in 1:nf
1,934✔
1616
            tag = Int32(read(s.io, UInt8)::UInt8)
3,558✔
1617
            if tag != UNDEFREF_TAG
3,558✔
1618
                f = handle_deserialize(s, tag)
3,557✔
1619
                na >= i && (vflds[i] = f)
3,557✔
1620
            else
1621
                na >= i && (na = i - 1) # rest of tail must be undefined values
1✔
1622
            end
1623
        end
5,182✔
1624
        return ccall(:jl_new_structv, Any, (Any, Ptr{Any}, UInt32), t, vflds, na)
1,934✔
1625
    end
1626
end
1627

1628
function deserialize_dict(s::AbstractSerializer, T::Type{<:AbstractDict})
4✔
1629
    n = read(s.io, Int32)
4✔
1630
    t = T(); sizehint!(t, n)
6✔
1631
    deserialize_cycle(s, t)
4✔
1632
    for i = 1:n
4✔
1633
        k = deserialize(s)
5✔
1634
        v = deserialize(s)
5✔
1635
        t[k] = v
5✔
1636
    end
7✔
1637
    return t
4✔
1638
end
1639

1640
function deserialize(s::AbstractSerializer, T::Type{Dict{K,V}}) where {K,V}
2✔
1641
    return deserialize_dict(s, T)
2✔
1642
end
1643

1644
deserialize(s::AbstractSerializer, ::Type{BigInt}) = parse(BigInt, deserialize(s), base = 62)
1✔
1645

1646
function deserialize(s::AbstractSerializer, t::Type{Regex})
1✔
1647
    pattern = deserialize(s)
1✔
1648
    compile_options = deserialize(s)
1✔
1649
    match_options = deserialize(s)
1✔
1650
    return Regex(pattern, compile_options, match_options)
1✔
1651
end
1652

1653
## StackTraces
1654

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

1669
function deserialize(s::AbstractSerializer, ::Type{Base.StackTraces.StackFrame})
1✔
1670
    func = deserialize(s)
1✔
1671
    file = deserialize(s)
1✔
1672
    line = read(s.io, Int)
1✔
1673
    from_c = read(s.io, Bool)
1✔
1674
    inlined = read(s.io, Bool)
1✔
1675
    pointer = read(s.io, UInt64)
1✔
1676
    return Base.StackTraces.StackFrame(func, file, line, nothing, from_c, inlined, pointer)
1✔
1677
end
1678

1679
function serialize(s::AbstractSerializer, lock::Base.AbstractLock)
1680
    # assert_havelock(lock)
1681
    serialize_cycle_header(s, lock)
2✔
1682
    nothing
1683
end
1684

1685
function deserialize(s::AbstractSerializer, ::Type{T}) where T<:Base.AbstractLock
1✔
1686
    lock = T()
1✔
1687
    deserialize_cycle(s, lock)
1✔
1688
    return lock
1✔
1689
end
1690

1691
function serialize(s::AbstractSerializer, cond::Base.GenericCondition)
1692
    serialize_cycle_header(s, cond) && return
4✔
1693
    serialize(s, cond.lock)
2✔
1694
    nothing
1695
end
1696

1697
function deserialize(s::AbstractSerializer, ::Type{T}) where T<:Base.GenericCondition
2✔
1698
    lock = deserialize(s)
2✔
1699
    cond = T(lock)
2✔
1700
    deserialize_cycle(s, cond)
2✔
1701
    return cond
2✔
1702
end
1703

1704
serialize(s::AbstractSerializer, l::LazyString) =
1✔
1705
    invoke(serialize, Tuple{AbstractSerializer,Any}, s, Base._LazyString((), string(l)))
1706

1707
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