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

JuliaLang / julia / #37666

04 Nov 2023 02:27AM UTC coverage: 87.924% (+0.09%) from 87.831%
#37666

push

local

web-flow
Simplify, 16bit PDP-11 isn't going to be supported (#45763)

PDP_ENDIAN isn't used.

Co-authored-by: Viral B. Shah <ViralBShah@users.noreply.github.com>

74550 of 84789 relevant lines covered (87.92%)

15319904.67 hits per line

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

88.63
/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: GMP, Bottom, unsafe_convert, uncompressed_ast
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)
219✔
27
end
28

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

85
format_version(::AbstractSerializer) = ser_version
5,477✔
86
format_version(s::Serializer) = s.version
114✔
87

88
function sertag(@nospecialize(v))
570,076✔
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)
570,076✔
92
    ptags = convert(Ptr{Ptr{Cvoid}}, pointer(TAGS))
570,076✔
93
    # note: constant ints & reserved slots never returned here
94
    @inbounds for i in 1:(NTAGS-(n_reserved_slots+2*n_int_literals))
21,862,347✔
95
        ptr == unsafe_load(ptags,i) && return i%Int32
74,484,911✔
96
    end
148,156,681✔
97
    return Int32(-1)
327,011✔
98
end
99
desertag(i::Int32) = @inbounds(TAGS[i])
465,275✔
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)
2,262,813✔
146

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

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

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

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

187
serialize(s::AbstractSerializer, x::Bool) = x ? writetag(s.io, TRUE_TAG) :
10,711✔
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)
59,115✔
193

194
function serialize(s::AbstractSerializer, t::Tuple)
32,712✔
195
    l = length(t)
32,712✔
196
    if l <= NTAGS
32,712✔
197
        writetag(s.io, TUPLE_TAG)
32,711✔
198
        write(s.io, UInt8(l))
32,738✔
199
    else
200
        writetag(s.io, LONGTUPLE_TAG)
1✔
201
        write(s.io, Int32(l))
1✔
202
    end
203
    for x in t
32,712✔
204
        serialize(s, x)
75,736✔
205
    end
55,893✔
206
end
207

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

216
function serialize(s::AbstractSerializer, x::Symbol)
186,835✔
217
    tag = sertag(x)
29,988,195✔
218
    if tag > 0
186,835✔
219
        return write_as_tag(s.io, tag)
63,379✔
220
    end
221
    pname = unsafe_convert(Ptr{UInt8}, x)
123,456✔
222
    len = Int(ccall(:strlen, Csize_t, (Cstring,), pname))
123,456✔
223
    if len > 7
123,456✔
224
        serialize_cycle(s, x) && return
74,039✔
225
    end
226
    if len <= NTAGS
116,983✔
227
        writetag(s.io, SYMBOL_TAG)
116,979✔
228
        write(s.io, UInt8(len))
117,252✔
229
    else
230
        writetag(s.io, LONGSYMBOL_TAG)
4✔
231
        write(s.io, Int32(len))
4✔
232
    end
233
    unsafe_write(s.io, pname, len)
116,983✔
234
    nothing
116,983✔
235
end
236

237
function serialize_array_data(s::IO, a)
5,036✔
238
    require_one_based_indexing(a)
5,036✔
239
    isempty(a) && return 0
5,036✔
240
    if eltype(a) === Bool
5,030✔
241
        last = a[1]::Bool
1✔
242
        count = 1
1✔
243
        for i = 2:length(a)
2✔
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)
5,029✔
255
    end
256
end
257

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

284
function serialize(s::AbstractSerializer, a::SubArray{T,N,A}) where {T,N,A<:Array}
14✔
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)
14✔
288
    serialize_any(s, b)
14✔
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)
211,105✔
317
    len = sizeof(ss)
211,105✔
318
    if len > 7
211,105✔
319
        serialize_cycle(s, ss) && return
209,571✔
320
        writetag(s.io, SHARED_REF_TAG)
202,171✔
321
    end
322
    if len <= NTAGS
203,705✔
323
        writetag(s.io, STRING_TAG)
203,616✔
324
        write(s.io, UInt8(len))
203,639✔
325
    else
326
        writetag(s.io, LONGSTRING_TAG)
89✔
327
        write(s.io, Int64(len))
89✔
328
    end
329
    write(s.io, ss)
203,705✔
330
    nothing
203,705✔
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)
1✔
343
    serialize(s, r.match_options)
1✔
344
end
345

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

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

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

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

380
function serialize(s::AbstractSerializer, d::IdDict)
2✔
381
    serialize_cycle(s, d) && return
2✔
382
    writetag(s.io, IDDICT_TAG)
2✔
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)
86,493✔
388
    p = parentmodule(m)
86,493✔
389
    if p === m || m === Base
114,719✔
390
        key = Base.root_module_key(m)
86,318✔
391
        uuid = key.uuid
86,318✔
392
        serialize(s, uuid === nothing ? nothing : uuid.value)
113,954✔
393
        serialize(s, Symbol(key.name))
86,318✔
394
    else
395
        serialize_mod_names(s, p)
175✔
396
        serialize(s, nameof(m))
175✔
397
    end
398
end
399

400
function serialize(s::AbstractSerializer, m::Module)
86,318✔
401
    writetag(s.io, MODULE_TAG)
86,318✔
402
    serialize_mod_names(s, m)
86,318✔
403
    writetag(s.io, EMPTYTUPLE_TAG)
86,318✔
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))
16✔
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)
18✔
425
    return get(s.known_object_data, n, nothing)
20✔
426
end
427

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

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

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

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

506
function serialize(s::AbstractSerializer, g::GlobalRef)
1,779✔
507
    if (g.mod === __deserialized_types__ ) ||
3,557✔
508
        (g.mod === Main && isdefined(g.mod, g.name) && isconst(g.mod, g.name))
509

510
        v = getglobal(g.mod, g.name)
450✔
511
        unw = unwrap_unionall(v)
450✔
512
        if isa(unw,DataType) && v === unw.name.wrapper && should_send_whole_type(s, unw)
478✔
513
            # handle references to types in Main by sending the whole type.
514
            # needed to be able to send nested functions (#15451).
515
            writetag(s.io, FULL_GLOBALREF_TAG)
13✔
516
            serialize(s, v)
13✔
517
            return
13✔
518
        end
519
    end
520
    writetag(s.io, GLOBALREF_TAG)
1,766✔
521
    serialize(s, g.mod)
1,766✔
522
    serialize(s, g.name)
1,766✔
523
end
524

525
function serialize(s::AbstractSerializer, t::Core.TypeName)
19✔
526
    serialize_cycle(s, t) && return
19✔
527
    writetag(s.io, TYPENAME_TAG)
8✔
528
    write(s.io, object_number(s, t))
15✔
529
    serialize_typename(s, t)
8✔
530
end
531

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

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

580
function serialize_type_data(s, @nospecialize(t::DataType))
114,226✔
581
    whole = should_send_whole_type(s, t)
227,919✔
582
    iswrapper = (t === unwrap_unionall(t.name.wrapper))
114,226✔
583
    if whole && iswrapper
114,226✔
584
        writetag(s.io, WRAPPER_DATATYPE_TAG)
1,378✔
585
        serialize(s, t.name)
1,378✔
586
        return
1,378✔
587
    end
588
    serialize_cycle(s, t) && return
112,848✔
589
    if whole
83,221✔
590
        writetag(s.io, FULL_DATATYPE_TAG)
262✔
591
        serialize(s, t.name)
262✔
592
    else
593
        writetag(s.io, DATATYPE_TAG)
82,959✔
594
        serialize(s, nameof(t))
82,959✔
595
        serialize(s, parentmodule(t))
82,959✔
596
    end
597
    if !isempty(t.parameters)
83,221✔
598
        if iswrapper
56,480✔
599
            write(s.io, Int32(0))
4✔
600
        else
601
            write(s.io, Int32(length(t.parameters)))
56,476✔
602
            for p in t.parameters
112,952✔
603
                serialize(s, p)
155,897✔
604
            end
155,897✔
605
        end
606
    end
607
    nothing
83,221✔
608
end
609

610
function serialize(s::AbstractSerializer, t::DataType)
117,478✔
611
    tag = sertag(t)
9,182,968✔
612
    tag > 0 && return write_as_tag(s.io, tag)
117,478✔
613
    if t === Tuple
30,769✔
614
        # `sertag` is not able to find types === to `Tuple` because they
615
        # will not have been hash-consed. Plus `serialize_type_data` does not
616
        # handle this case correctly, since Tuple{} != Tuple. `Tuple` is the
617
        # only type with this property. issue #15849
618
        return write_as_tag(s.io, TUPLE_TAG)
×
619
    end
620
    serialize_type_data(s, t)
30,769✔
621
end
622

623
function serialize_type(s::AbstractSerializer, @nospecialize(t::DataType), ref::Bool = false)
90,996✔
624
    tag = sertag(t)
14,084,118✔
625
    tag > 0 && return writetag(s.io, tag)
90,140✔
626
    writetag(s.io, ref ? REF_OBJECT_TAG : OBJECT_TAG)
83,455✔
627
    serialize_type_data(s, t)
83,455✔
628
end
629

630
function serialize(s::AbstractSerializer, n::Int32)
3,069✔
631
    if 0 <= n <= (n_int_literals-1)
3,069✔
632
        write(s.io, UInt8(ZERO32_TAG+n))
1,786✔
633
    else
634
        writetag(s.io, INT32_TAG)
1,313✔
635
        write(s.io, n)
1,313✔
636
    end
637
    nothing
3,069✔
638
end
639

640
function serialize(s::AbstractSerializer, n::Int64)
73,371✔
641
    if 0 <= n <= (n_int_literals-1)
73,371✔
642
        write(s.io, UInt8(ZERO64_TAG+n))
43,833✔
643
    elseif typemin(Int32) <= n <= typemax(Int32)
30,119✔
644
        writetag(s.io, SHORTINT64_TAG)
29,972✔
645
        write(s.io, Int32(n))
29,972✔
646
    else
647
        writetag(s.io, INT64_TAG)
147✔
648
        write(s.io, n)
147✔
649
    end
650
    nothing
73,371✔
651
end
652

653
for i in 0:13
654
    tag = Int32(INT8_TAG + i)
655
    ty = TAGS[tag]
656
    (ty === Int32 || ty === Int64) && continue
657
    @eval serialize(s::AbstractSerializer, n::$ty) = (writetag(s.io, $tag); write(s.io, n); nothing)
165,981✔
658
end
659

660
serialize(s::AbstractSerializer, ::Type{Bottom}) = write_as_tag(s.io, BOTTOM_TAG)
24,403✔
661

662
function serialize(s::AbstractSerializer, u::UnionAll)
129✔
663
    writetag(s.io, UNIONALL_TAG)
129✔
664
    n = 0; t = u
258✔
665
    while isa(t, UnionAll)
357✔
666
        t = t.body
228✔
667
        n += 1
228✔
668
    end
228✔
669
    if isa(t, DataType) && t === unwrap_unionall(t.name.wrapper)
129✔
670
        write(s.io, UInt8(1))
136✔
671
        write(s.io, Int16(n))
127✔
672
        serialize(s, t)
127✔
673
    else
674
        write(s.io, UInt8(0))
4✔
675
        serialize(s, u.var)
2✔
676
        serialize(s, u.body)
2✔
677
    end
678
end
679

680
serialize(s::AbstractSerializer, @nospecialize(x)) = serialize_any(s, x)
175,548✔
681

682
function serialize(s::AbstractSerializer, x::Core.AddrSpace)
13✔
683
    serialize_type(s, typeof(x))
13✔
684
    write(s.io, Core.bitcast(UInt8, x))
13✔
685
end
686

687
function serialize_any(s::AbstractSerializer, @nospecialize(x))
175,570✔
688
    tag = sertag(x)
21,555,588✔
689
    if tag > 0
175,570✔
690
        return write_as_tag(s.io, tag)
86,239✔
691
    end
692
    t = typeof(x)::DataType
89,331✔
693
    if isprimitivetype(t)
89,331✔
694
        serialize_type(s, t)
12✔
695
        write(s.io, x)
12✔
696
    else
697
        if ismutable(x)
89,319✔
698
            serialize_cycle(s, x) && return
3,484✔
699
            serialize_type(s, t, true)
3,259✔
700
        else
701
            serialize_type(s, t, false)
85,835✔
702
        end
703
        nf = nfields(x)
89,094✔
704
        for i in 1:nf
129,792✔
705
            if isdefined(x, i)
97,065✔
706
                serialize(s, getfield(x, i))
97,064✔
707
            else
708
                writetag(s.io, UNDEFREF_TAG)
1✔
709
            end
710
        end
97,065✔
711
    end
712
    nothing
89,106✔
713
end
714

715
"""
716
    Serialization.writeheader(s::AbstractSerializer)
717

718
Write an identifying header to the specified serializer. The header consists of
719
8 bytes as follows:
720

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

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

780
"""
781
    serialize(stream::IO, value)
782

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

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

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

800
In some cases, the word size (32- or 64-bit) of the reading and writing machines must match.
801
In rarer cases the OS or architecture must also match, for example when using packages
802
that contain platform-dependent code.
803
"""
804
function serialize(s::IO, x)
115✔
805
    ss = Serializer(s)
115✔
806
    writeheader(ss)
115✔
807
    serialize(ss, x)
116✔
808
end
809

810
"""
811
    serialize(filename::AbstractString, value)
812

813
Open a file and serialize the given value to it.
814

815
!!! compat "Julia 1.1"
816
    This method is available as of Julia 1.1.
817
"""
818
serialize(filename::AbstractString, x) = open(io->serialize(io, x), filename, "w")
2✔
819

820
## deserializing values ##
821

822
"""
823
    deserialize(stream)
824

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

833
"""
834
    deserialize(filename::AbstractString)
835

836
Open a file and deserialize its contents.
837

838
!!! compat "Julia 1.1"
839
    This method is available as of Julia 1.1.
840
"""
841
deserialize(filename::AbstractString) = open(deserialize, filename)
1✔
842

843
function deserialize(s::AbstractSerializer)
1,074,787✔
844
    handle_deserialize(s, Int32(read(s.io, UInt8)::UInt8))
1,074,787✔
845
end
846

847
function deserialize_cycle(s::AbstractSerializer, @nospecialize(x))
4,942✔
848
    slot = pop!(s.pending_refs)
4,942✔
849
    s.table[slot] = x
4,942✔
850
    nothing
4,942✔
851
end
852

853
# optimized version of:
854
#     slot = s.counter; s.counter += 1
855
#     push!(s.pending_refs, slot)
856
#     slot = pop!(s.pending_refs)
857
#     s.table[slot] = x
858
function resolve_ref_immediately(s::AbstractSerializer, @nospecialize(x))
71,010✔
859
    s.table[s.counter] = x
71,010✔
860
    s.counter += 1
71,010✔
861
    nothing
71,010✔
862
end
863

864
function gettable(s::AbstractSerializer, id::Int)
44,098✔
865
    get(s.table, id) do
44,098✔
866
        errmsg = """Inconsistent Serializer state when deserializing.
×
867
            Attempt to access internal table with key $id failed.
868

869
            This might occur if the Serializer contexts when serializing and deserializing are inconsistent.
870
            In particular, if multiple serialize calls use the same Serializer object then
871
            the corresponding deserialize calls should also use the same Serializer object.
872
        """
873
        error(errmsg)
×
874
    end
875
end
876

877
# deserialize_ is an internal function to dispatch on the tag
878
# describing the serialized representation. the number of
879
# representations is fixed, so deserialize_ does not get extended.
880
function handle_deserialize(s::AbstractSerializer, b::Int32)
1,419,884✔
881
    if b == 0
1,419,884✔
882
        return desertag(Int32(read(s.io, UInt8)::UInt8))
33,314✔
883
    end
884
    if b >= VALUE_TAGS
1,386,570✔
885
        return desertag(b)
423,670✔
886
    elseif b == TUPLE_TAG
962,900✔
887
        return deserialize_tuple(s, Int(read(s.io, UInt8)::UInt8))
32,538✔
888
    elseif b == SHORTBACKREF_TAG
930,362✔
889
        id = read(s.io, UInt16)::UInt16
44,097✔
890
        return gettable(s, Int(id))
44,097✔
891
    elseif b == BACKREF_TAG
886,265✔
892
        id = read(s.io, Int32)::Int32
1✔
893
        return gettable(s, Int(id))
1✔
894
    elseif b == ARRAY_TAG
886,264✔
895
        return deserialize_array(s)
9,065✔
896
    elseif b == DATATYPE_TAG
877,199✔
897
        return deserialize_datatype(s, false)
82,611✔
898
    elseif b == FULL_DATATYPE_TAG
794,588✔
899
        return deserialize_datatype(s, true)
267✔
900
    elseif b == WRAPPER_DATATYPE_TAG
794,321✔
901
        tname = deserialize(s)::Core.TypeName
1,381✔
902
        return unwrap_unionall(tname.wrapper)
1,377✔
903
    elseif b == OBJECT_TAG
792,940✔
904
        t = deserialize(s)
80,509✔
905
        if t === Missing
80,505✔
906
            return missing
×
907
        end
908
        return deserialize(s, t)
80,505✔
909
    elseif b == REF_OBJECT_TAG
712,431✔
910
        slot = s.counter; s.counter += 1
5,208✔
911
        push!(s.pending_refs, slot)
2,604✔
912
        t = deserialize(s)
2,604✔
913
        return deserialize(s, t)
2,603✔
914
    elseif b == SHARED_REF_TAG
709,827✔
915
        slot = s.counter; s.counter += 1
404,246✔
916
        obj = deserialize(s)
202,123✔
917
        s.table[slot] = obj
202,123✔
918
        return obj
202,123✔
919
    elseif b == SYMBOL_TAG
507,704✔
920
        return deserialize_symbol(s, Int(read(s.io, UInt8)::UInt8))
116,298✔
921
    elseif b == SHORTINT64_TAG
391,406✔
922
        return Int64(read(s.io, Int32)::Int32)
29,827✔
923
    elseif b == EXPR_TAG
361,579✔
924
        return deserialize_expr(s, Int(read(s.io, UInt8)::UInt8))
3,903✔
925
    elseif b == MODULE_TAG
357,676✔
926
        return deserialize_module(s)
85,964✔
927
    elseif b == STRING_TAG
271,712✔
928
        return deserialize_string(s, Int(read(s.io, UInt8)::UInt8))
203,546✔
929
    elseif b == LONGSTRING_TAG
68,166✔
930
        return deserialize_string(s, Int(read(s.io, Int64)::Int64))
89✔
931
    elseif b == SIMPLEVECTOR_TAG
68,077✔
932
        return deserialize_svec(s)
1,294✔
933
    elseif b == GLOBALREF_TAG
66,783✔
934
        return GlobalRef(deserialize(s)::Module, deserialize(s)::Symbol)
1,771✔
935
    elseif b == FULL_GLOBALREF_TAG
65,012✔
936
        ty = deserialize(s)
13✔
937
        tn = unwrap_unionall(ty).name
13✔
938
        return GlobalRef(tn.module, tn.name)
13✔
939
    elseif b == LONGTUPLE_TAG
64,999✔
940
        return deserialize_tuple(s, Int(read(s.io, Int32)::Int32))
1✔
941
    elseif b == LONGEXPR_TAG
64,998✔
942
        return deserialize_expr(s, Int(read(s.io, Int32)::Int32))
1✔
943
    elseif b == LONGBACKREF_TAG
64,997✔
944
        id = read(s.io, Int64)::Int64
×
945
        return gettable(s, Int(id))
×
946
    elseif b == LONGSYMBOL_TAG
64,997✔
947
        return deserialize_symbol(s, Int(read(s.io, Int32)::Int32))
4✔
948
    elseif b == HEADER_TAG
64,993✔
949
        readheader(s)
105✔
950
        return deserialize(s)
101✔
951
    elseif b == INT8_TAG
64,888✔
952
        return read(s.io, Int8)
20✔
953
    elseif b == INT8_TAG+1
64,868✔
954
        return read(s.io, UInt8)
2,853✔
955
    elseif b == INT8_TAG+2
62,015✔
956
        return read(s.io, Int16)
12✔
957
    elseif b == INT8_TAG+3
62,003✔
958
        return read(s.io, UInt16)
441✔
959
    elseif b == INT32_TAG
61,562✔
960
        return read(s.io, Int32)
1,314✔
961
    elseif b == INT8_TAG+5
60,248✔
962
        return read(s.io, UInt32)
15✔
963
    elseif b == INT64_TAG
60,233✔
964
        return read(s.io, Int64)
149✔
965
    elseif b == INT8_TAG+7
60,084✔
966
        return read(s.io, UInt64)
1,292✔
967
    elseif b == INT8_TAG+8
58,792✔
968
        return read(s.io, Int128)
11,074✔
969
    elseif b == INT8_TAG+9
47,718✔
970
        return read(s.io, UInt128)
27,767✔
971
    elseif b == INT8_TAG+10
19,951✔
972
        return read(s.io, Float16)
4✔
973
    elseif b == INT8_TAG+11
19,947✔
974
        return read(s.io, Float32)
×
975
    elseif b == INT8_TAG+12
19,947✔
976
        return read(s.io, Float64)
517✔
977
    elseif b == INT8_TAG+13
19,430✔
978
        return read(s.io, Char)
11,137✔
979
    elseif b == IDDICT_TAG
8,293✔
980
        slot = s.counter; s.counter += 1
4✔
981
        push!(s.pending_refs, slot)
2✔
982
        t = deserialize(s)
2✔
983
        return deserialize_dict(s, t)
2✔
984
    end
985
    t = desertag(b)::DataType
8,291✔
986
    if ismutabletype(t) && length(t.types) > 0  # manual specialization of fieldcount
8,291✔
987
        slot = s.counter; s.counter += 1
4,682✔
988
        push!(s.pending_refs, slot)
2,341✔
989
    end
990
    return deserialize(s, t)
8,291✔
991
end
992

993
function deserialize_symbol(s::AbstractSerializer, len::Int)
116,302✔
994
    str = Base._string_n(len)
116,302✔
995
    unsafe_read(s.io, pointer(str), len)
116,302✔
996
    sym = Symbol(str)
116,302✔
997
    if len > 7
116,302✔
998
        resolve_ref_immediately(s, sym)
67,106✔
999
    end
1000
    return sym
116,302✔
1001
end
1002

1003
deserialize_tuple(s::AbstractSerializer, len) = ntupleany(i->deserialize(s), len)
88,046✔
1004

1005
function deserialize_svec(s::AbstractSerializer)
1,294✔
1006
    n = read(s.io, Int32)
1,294✔
1007
    svec(Any[ deserialize(s) for i=1:n ]...)
1,294✔
1008
end
1009

1010
function deserialize_module(s::AbstractSerializer)
85,964✔
1011
    mkey = deserialize(s)
85,964✔
1012
    if isa(mkey, Tuple)
85,964✔
1013
        # old version, TODO: remove
1014
        if mkey === ()
×
1015
            return Main
×
1016
        end
1017
        m = Base.root_module(mkey[1])
×
1018
        for i = 2:length(mkey)
×
1019
            m = getglobal(m, mkey[i])::Module
×
1020
        end
×
1021
    else
1022
        name = String(deserialize(s)::Symbol)
85,964✔
1023
        pkg = (mkey === nothing) ? Base.PkgId(name) : Base.PkgId(Base.UUID(mkey), name)
113,497✔
1024
        m = Base.root_module(pkg)
85,964✔
1025
        mname = deserialize(s)
85,964✔
1026
        while mname !== ()
86,137✔
1027
            m = getglobal(m, mname)::Module
175✔
1028
            mname = deserialize(s)
173✔
1029
        end
173✔
1030
    end
1031
    return m
85,962✔
1032
end
1033

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

1120
function deserialize(s::AbstractSerializer, ::Type{Core.MethodInstance})
×
1121
    linfo = ccall(:jl_new_method_instance_uninit, Ref{Core.MethodInstance}, (Ptr{Cvoid},), C_NULL)
×
1122
    deserialize_cycle(s, linfo)
×
1123
    tag = Int32(read(s.io, UInt8)::UInt8)
×
1124
    if tag != UNDEFREF_TAG
×
1125
        setfield!(linfo, :uninferred, handle_deserialize(s, tag)::CodeInfo, :monotonic)
×
1126
    end
1127
    tag = Int32(read(s.io, UInt8)::UInt8)
×
1128
    if tag != UNDEFREF_TAG
×
1129
        # for reading files prior to v1.2
1130
        handle_deserialize(s, tag)
×
1131
    end
1132
    linfo.sparam_vals = deserialize(s)::SimpleVector
×
1133
    _rettype = deserialize(s)  # for backwards compat
×
1134
    linfo.specTypes = deserialize(s)
×
1135
    linfo.def = deserialize(s)
×
1136
    return linfo
×
1137
end
1138

1139
function deserialize(s::AbstractSerializer, ::Type{Core.LineInfoNode})
885✔
1140
    mod = deserialize(s)
885✔
1141
    if mod isa Module
885✔
1142
        method = deserialize(s)
885✔
1143
    else
1144
        # files post v1.2 and pre v1.6 are broken
1145
        method = mod
×
1146
        mod = Main
×
1147
    end
1148
    return Core.LineInfoNode(mod, method, deserialize(s)::Symbol, Int32(deserialize(s)::Union{Int32, Int}), Int32(deserialize(s)::Union{Int32, Int}))
885✔
1149
end
1150

1151
function deserialize(s::AbstractSerializer, ::Type{PhiNode})
×
1152
    edges = deserialize(s)
×
1153
    if edges isa Vector{Any}
×
1154
        edges = Vector{Int32}(edges)
×
1155
    end
1156
    values = deserialize(s)::Vector{Any}
×
1157
    return PhiNode(edges, values)
×
1158
end
1159

1160
function deserialize(s::AbstractSerializer, ::Type{CodeInfo})
431✔
1161
    ci = ccall(:jl_new_code_info_uninit, Ref{CodeInfo}, ())
431✔
1162
    deserialize_cycle(s, ci)
431✔
1163
    code = deserialize(s)::Vector{Any}
431✔
1164
    ci.code = code
430✔
1165
    # allow older-style IR with return and gotoifnot Exprs
1166
    for i in 1:length(code)
860✔
1167
        stmt = code[i]
2,677✔
1168
        if isa(stmt, Expr)
2,677✔
1169
            ex = stmt::Expr
1,666✔
1170
            if ex.head === :return
1,666✔
1171
                code[i] = ReturnNode(isempty(ex.args) ? nothing : ex.args[1])
1✔
1172
            elseif ex.head === :gotoifnot
1,665✔
1173
                code[i] = GotoIfNot(ex.args[1], ex.args[2])
×
1174
            end
1175
        end
1176
    end
4,924✔
1177
    ci.codelocs = deserialize(s)::Vector{Int32}
430✔
1178
    _x = deserialize(s)
430✔
1179
    if _x isa Array || _x isa Int
860✔
1180
        pre_12 = false
429✔
1181
        ci.ssavaluetypes = _x
429✔
1182
    else
1183
        pre_12 = true
1✔
1184
        # < v1.2
1185
        ci.method_for_inference_limit_heuristics = _x
1✔
1186
        ci.ssavaluetypes = deserialize(s)
1✔
1187
        ci.linetable = deserialize(s)
1✔
1188
    end
1189
    ssaflags = deserialize(s)
430✔
1190
    if length(ssaflags) ≠ length(code)
430✔
1191
        # make sure the length of `ssaflags` matches that of `code`
1192
        # so that the latest inference doesn't throw on IRs serialized from old versions
1193
        ssaflags = UInt32[0x00 for _ in 1:length(code)]
3✔
1194
    elseif eltype(ssaflags) != UInt32
429✔
1195
        ssaflags = map(UInt32, ssaflags)
×
1196
    end
1197
    ci.ssaflags = ssaflags
430✔
1198
    if pre_12
430✔
1199
        ci.slotflags = deserialize(s)
1✔
1200
    else
1201
        ci.method_for_inference_limit_heuristics = deserialize(s)
429✔
1202
        ci.linetable = deserialize(s)
429✔
1203
    end
1204
    ci.slotnames = deserialize(s)
430✔
1205
    if !pre_12
430✔
1206
        ci.slotflags = deserialize(s)
429✔
1207
        ci.slottypes = deserialize(s)
429✔
1208
        ci.rettype = deserialize(s)
429✔
1209
        ci.parent = deserialize(s)
429✔
1210
        world_or_edges = deserialize(s)
429✔
1211
        pre_13 = isa(world_or_edges, Integer)
429✔
1212
        if pre_13
429✔
1213
            ci.min_world = world_or_edges
×
1214
        else
1215
            ci.edges = world_or_edges
429✔
1216
            ci.min_world = reinterpret(UInt, deserialize(s))
429✔
1217
            ci.max_world = reinterpret(UInt, deserialize(s))
429✔
1218
        end
1219
    end
1220
    ci.inferred = deserialize(s)
430✔
1221
    if format_version(s) < 22
430✔
1222
        inlining_cost = deserialize(s)
1✔
1223
        if isa(inlining_cost, Bool)
1✔
1224
            Core.Compiler.set_inlineable!(ci, inlining_cost)
1✔
1225
        else
1226
            ci.inlining_cost = inlining_cost
×
1227
        end
1228
    end
1229
    ci.propagate_inbounds = deserialize(s)
430✔
1230
    if format_version(s) < 23
430✔
1231
        deserialize(s) # `pure` field has been removed
1✔
1232
    end
1233
    if format_version(s) >= 20
430✔
1234
        ci.has_fcall = deserialize(s)
429✔
1235
    end
1236
    if format_version(s) >= 24
430✔
1237
        ci.nospecializeinfer = deserialize(s)::Bool
429✔
1238
    end
1239
    if format_version(s) >= 21
430✔
1240
        ci.inlining = deserialize(s)::UInt8
429✔
1241
    end
1242
    if format_version(s) >= 14
430✔
1243
        ci.constprop = deserialize(s)::UInt8
429✔
1244
    end
1245
    if format_version(s) >= 17
430✔
1246
        ci.purity = deserialize(s)::UInt8
429✔
1247
    end
1248
    if format_version(s) >= 22
430✔
1249
        ci.inlining_cost = deserialize(s)::UInt16
429✔
1250
    end
1251
    return ci
430✔
1252
end
1253

1254
if Int === Int64
1255
const OtherInt = Int32
1256
else
1257
const OtherInt = Int64
1258
end
1259

1260
function deserialize_array(s::AbstractSerializer)
9,065✔
1261
    slot = s.counter; s.counter += 1
18,130✔
1262
    d1 = deserialize(s)
9,065✔
1263
    if isa(d1, Type)
9,065✔
1264
        elty = d1
8,630✔
1265
        d1 = deserialize(s)
8,630✔
1266
    else
1267
        elty = UInt8
435✔
1268
    end
1269
    if isa(d1, Int32) || isa(d1, Int64)
18,130✔
1270
        if elty !== Bool && isbitstype(elty)
9,233✔
1271
            a = Vector{elty}(undef, d1)
4,946✔
1272
            s.table[slot] = a
4,946✔
1273
            return read!(s.io, a)
4,946✔
1274
        end
1275
        dims = (Int(d1),)
8,110✔
1276
    elseif d1 isa Dims
64✔
1277
        dims = d1::Dims
64✔
1278
    else
1279
        dims = convert(Dims, d1::Tuple{Vararg{OtherInt}})::Dims
×
1280
    end
1281
    if isbitstype(elty)
4,363✔
1282
        n = prod(dims)::Int
104✔
1283
        if elty === Bool && n > 0
52✔
1284
            A = Array{Bool, length(dims)}(undef, dims)
1✔
1285
            i = 1
1✔
1286
            while i <= n
6✔
1287
                b = read(s.io, UInt8)::UInt8
5✔
1288
                v = (b >> 7) != 0
5✔
1289
                count = b & 0x7f
5✔
1290
                nxt = i + count
5✔
1291
                while i < nxt
14✔
1292
                    A[i] = v
9✔
1293
                    i += 1
9✔
1294
                end
9✔
1295
            end
6✔
1296
        else
1297
            A = read!(s.io, Array{elty}(undef, dims))
51✔
1298
        end
1299
        s.table[slot] = A
52✔
1300
        return A
52✔
1301
    end
1302
    A = Array{elty, length(dims)}(undef, dims)
4,067✔
1303
    s.table[slot] = A
4,067✔
1304
    sizehint!(s.table, s.counter + div(length(A)::Int,4))
4,175✔
1305
    deserialize_fillarray!(A, s)
4,067✔
1306
    return A
4,065✔
1307
end
1308

1309
function deserialize_fillarray!(A::Union{Array{T},Memory{T}}, s::AbstractSerializer) where {T}
4,067✔
1310
    for i = eachindex(A)
6,931✔
1311
        tag = Int32(read(s.io, UInt8)::UInt8)
260,994✔
1312
        if tag != UNDEFREF_TAG
260,994✔
1313
            @inbounds A[i] = handle_deserialize(s, tag)
260,992✔
1314
        end
1315
    end
519,122✔
1316
    return A
4,065✔
1317
end
1318

1319
function deserialize(s::AbstractSerializer, X::Type{Memory{T}} where T)
×
1320
    slot = pop!(s.pending_refs) # e.g. deserialize_cycle
×
1321
    n = deserialize(s)::Int
×
1322
    elty = eltype(X)
×
1323
    if isbitstype(elty)
×
1324
        A = X(undef, n)
×
1325
        if X === Memory{Bool}
×
1326
            i = 1
×
1327
            while i <= n
×
1328
                b = read(s.io, UInt8)::UInt8
×
1329
                v = (b >> 7) != 0
×
1330
                count = b & 0x7f
×
1331
                nxt = i + count
×
1332
                while i < nxt
×
1333
                    A[i] = v
×
1334
                    i += 1
×
1335
                end
×
1336
            end
×
1337
        else
1338
            A = read!(s.io, A)::X
×
1339
        end
1340
        s.table[slot] = A
×
1341
        return A
×
1342
    end
1343
    A = X(undef, n)
×
1344
    s.table[slot] = A
×
1345
    sizehint!(s.table, s.counter + div(n, 4))
×
1346
    deserialize_fillarray!(A, s)
×
1347
    return A
×
1348
end
1349

1350
function deserialize(s::AbstractSerializer, X::Type{MemoryRef{T}} where T)
×
1351
    x = Core.memoryref(deserialize(s))::X
×
1352
    i = deserialize(s)::Int
×
1353
    i == 2 || (x = Core.memoryref(x, i, true))
×
1354
    return x::X
×
1355
end
1356

1357
function deserialize(s::AbstractSerializer, X::Type{Core.AddrSpace{M}} where M)
×
1358
    Core.bitcast(X, read(s.io, UInt8))
×
1359
end
1360

1361
function deserialize_expr(s::AbstractSerializer, len)
3,904✔
1362
    e = Expr(:temp)
3,904✔
1363
    resolve_ref_immediately(s, e)
3,904✔
1364
    e.head = deserialize(s)::Symbol
3,904✔
1365
    e.args = Any[ deserialize(s) for i = 1:len ]
9,191✔
1366
    e
3,904✔
1367
end
1368

1369
module __deserialized_types__ end
1370

1371
function deserialize(s::AbstractSerializer, ::Type{Core.TypeName})
9✔
1372
    number = read(s.io, UInt64)
9✔
1373
    return deserialize_typename(s, number)
9✔
1374
end
1375

1376
function deserialize_typename(s::AbstractSerializer, number)
431✔
1377
    name = deserialize(s)::Symbol
431✔
1378
    tn = lookup_object_number(s, number)
433✔
1379
    if tn !== nothing
431✔
1380
        makenew = false
2✔
1381
    else
1382
        # reuse the same name for the type, if possible, for nicer debugging
1383
        tn_name = isdefined(__deserialized_types__, name) ? gensym() : name
429✔
1384
        tn = ccall(:jl_new_typename_in, Any, (Any, Any, Cint, Cint),
429✔
1385
                   tn_name, __deserialized_types__, false, false)
1386
        makenew = true
429✔
1387
    end
1388
    tn = tn::Core.TypeName
431✔
1389
    remember_object(s, tn, number)
431✔
1390
    deserialize_cycle(s, tn)
431✔
1391

1392
    names = deserialize(s)::SimpleVector
431✔
1393
    super = deserialize(s)::Type
431✔
1394
    parameters = deserialize(s)::SimpleVector
431✔
1395
    types = deserialize(s)::SimpleVector
431✔
1396
    attrs = Core.svec()
431✔
1397
    has_instance = deserialize(s)::Bool
431✔
1398
    abstr = deserialize(s)::Bool
431✔
1399
    mutabl = deserialize(s)::Bool
431✔
1400
    ninitialized = deserialize(s)::Int32
431✔
1401
    maxm = format_version(s) >= 18 ? deserialize(s)::UInt8 : UInt8(0)
431✔
1402

1403
    if makenew
431✔
1404
        # TODO: there's an unhanded cycle in the dependency graph at this point:
1405
        # while deserializing super and/or types, we may have encountered
1406
        # tn.wrapper and throw UndefRefException before we get to this point
1407
        ndt = ccall(:jl_new_datatype, Any, (Any, Any, Any, Any, Any, Any, Any, Cint, Cint, Cint),
429✔
1408
                    tn, tn.module, super, parameters, names, types, attrs,
1409
                    abstr, mutabl, ninitialized)
1410
        @assert tn == ndt.name
429✔
1411
        ccall(:jl_set_const, Cvoid, (Any, Any, Any), tn.module, tn.name, tn.wrapper)
429✔
1412
        ty = tn.wrapper
429✔
1413
        tn.max_methods = maxm
429✔
1414
        if has_instance
429✔
1415
            ty = ty::DataType
305✔
1416
            if !isdefined(ty, :instance)
305✔
1417
                singleton = ccall(:jl_new_struct, Any, (Any, Any...), ty)
×
1418
                # use setfield! directly to avoid `fieldtype` lowering expecting to see a Singleton object already on ty
1419
                ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), ty, Base.fieldindex(DataType, :instance)-1, singleton)
×
1420
            end
1421
        end
1422
    end
1423

1424
    tag = Int32(read(s.io, UInt8)::UInt8)
431✔
1425
    if tag != UNDEFREF_TAG
431✔
1426
        mtname = handle_deserialize(s, tag)
430✔
1427
        defs = deserialize(s)
430✔
1428
        maxa = deserialize(s)::Int
429✔
1429
        if makenew
429✔
1430
            mt = ccall(:jl_new_method_table, Any, (Any, Any), name, tn.module)
427✔
1431
            if !isempty(parameters)
427✔
1432
                mt.offs = 0
118✔
1433
            end
1434
            mt.name = mtname
427✔
1435
            setfield!(mt, :max_args, maxa, :monotonic)
427✔
1436
            ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), tn, Base.fieldindex(Core.TypeName, :mt)-1, mt)
427✔
1437
            for def in defs
427✔
1438
                if isdefined(def, :sig)
427✔
1439
                    ccall(:jl_method_table_insert, Cvoid, (Any, Any, Ptr{Cvoid}), mt, def, C_NULL)
427✔
1440
                end
1441
            end
427✔
1442
        end
1443
        tag = Int32(read(s.io, UInt8)::UInt8)
429✔
1444
        if tag != UNDEFREF_TAG
429✔
1445
            kws = handle_deserialize(s, tag)
1✔
1446
            if makenew
1✔
1447
                if kws isa Vector{Method}
1✔
1448
                    for def in kws
1✔
1449
                        kwmt = typeof(Core.kwcall).name.mt
1✔
1450
                        ccall(:jl_method_table_insert, Cvoid, (Any, Any, Ptr{Cvoid}), mt, def, C_NULL)
1✔
1451
                    end
1✔
1452
                else
1453
                    # old object format -- try to forward from old to new
1454
                    @eval Core.kwcall(kwargs::NamedTuple, f::$ty, args...) = $kws(kwargs, f, args...)
429✔
1455
                end
1456
            end
1457
        end
1458
    elseif makenew
1✔
1459
        mt = Symbol.name.mt
1✔
1460
        ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), tn, Base.fieldindex(Core.TypeName, :mt)-1, mt)
1✔
1461
    end
1462
    return tn
430✔
1463
end
1464

1465
function deserialize_datatype(s::AbstractSerializer, full::Bool)
82,878✔
1466
    slot = s.counter; s.counter += 1
165,756✔
1467
    if full
82,878✔
1468
        tname = deserialize(s)::Core.TypeName
267✔
1469
        ty = tname.wrapper
267✔
1470
    else
1471
        name = deserialize(s)::Symbol
82,611✔
1472
        mod = deserialize(s)::Module
82,611✔
1473
        ty = getglobal(mod, name)
82,611✔
1474
    end
1475
    if isa(ty,DataType) && isempty(ty.parameters)
82,874✔
1476
        t = ty
26,633✔
1477
    else
1478
        np = Int(read(s.io, Int32)::Int32)
56,241✔
1479
        if np == 0
56,241✔
1480
            t = unwrap_unionall(ty)
4✔
1481
        elseif ty === Tuple
56,237✔
1482
            # note np==0 has its own tag
1483
            if np == 1
1,763✔
1484
                t = Tuple{deserialize(s)}
1,161✔
1485
            elseif np == 2
602✔
1486
                t = Tuple{deserialize(s), deserialize(s)}
478✔
1487
            elseif np == 3
124✔
1488
                t = Tuple{deserialize(s), deserialize(s), deserialize(s)}
85✔
1489
            elseif np == 4
39✔
1490
                t = Tuple{deserialize(s), deserialize(s), deserialize(s), deserialize(s)}
17✔
1491
            else
1492
                t = Tuple{Any[ deserialize(s) for i=1:np ]...}
1,785✔
1493
            end
1494
        else
1495
            t = ty
54,474✔
1496
            for i = 1:np
108,948✔
1497
                t = t{deserialize(s)}
152,669✔
1498
            end
152,669✔
1499
        end
1500
    end
1501
    s.table[slot] = t
82,874✔
1502
    return t
82,874✔
1503
end
1504

1505
function deserialize(s::AbstractSerializer, ::Type{UnionAll})
130✔
1506
    form = read(s.io, UInt8)
130✔
1507
    if form == 0
130✔
1508
        var = deserialize(s)
2✔
1509
        body = deserialize(s)
2✔
1510
        return UnionAll(var, body)
2✔
1511
    else
1512
        n = read(s.io, Int16)
128✔
1513
        t = deserialize(s)::DataType
128✔
1514
        w = t.name.wrapper
128✔
1515
        k = 0
128✔
1516
        while isa(w, UnionAll)
356✔
1517
            w = w.body
228✔
1518
            k += 1
228✔
1519
        end
228✔
1520
        w = t.name.wrapper
128✔
1521
        k -= n
128✔
1522
        while k > 0
128✔
1523
            w = w.body
×
1524
            k -= 1
×
1525
        end
×
1526
        return w
128✔
1527
    end
1528
end
1529

1530
function deserialize(s::AbstractSerializer, ::Type{Task})
3✔
1531
    t = Task(()->nothing)
3✔
1532
    deserialize_cycle(s, t)
3✔
1533
    t.code = deserialize(s)
3✔
1534
    t.storage = deserialize(s)
3✔
1535
    state = deserialize(s)
3✔
1536
    if state === :runnable
3✔
1537
        t._state = Base.task_state_runnable
×
1538
    elseif state === :done
3✔
1539
        t._state = Base.task_state_done
1✔
1540
    elseif state === :failed
2✔
1541
        t._state = Base.task_state_failed
2✔
1542
    else
1543
        @assert false
×
1544
    end
1545
    t.result = deserialize(s)
3✔
1546
    exc = deserialize(s)
3✔
1547
    if exc === nothing
3✔
1548
        t._isexception = false
×
1549
    elseif exc isa Bool
3✔
1550
        t._isexception = exc
3✔
1551
    else
1552
        t._isexception = true
×
1553
        t.result = exc
×
1554
    end
1555
    t
3✔
1556
end
1557

1558
function deserialize_string(s::AbstractSerializer, len::Int)
203,635✔
1559
    out = ccall(:jl_alloc_string, Ref{String}, (Csize_t,), len)
203,635✔
1560
    unsafe_read(s.io, pointer(out), len)
203,635✔
1561
    return out
203,635✔
1562
end
1563

1564
# default DataType deserializer
1565
function deserialize(s::AbstractSerializer, t::DataType)
87,567✔
1566
    nf = length(t.types)
87,567✔
1567
    if isprimitivetype(t)
87,567✔
1568
        return read(s.io, t)
12✔
1569
    elseif ismutabletype(t)
87,555✔
1570
        x = ccall(:jl_new_struct_uninit, Any, (Any,), t)
2,956✔
1571
        deserialize_cycle(s, x)
2,956✔
1572
        for i in 1:nf
5,910✔
1573
            tag = Int32(read(s.io, UInt8)::UInt8)
9,317✔
1574
            if tag != UNDEFREF_TAG
9,317✔
1575
                ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), x, i-1, handle_deserialize(s, tag))
8,864✔
1576
            end
1577
        end
15,680✔
1578
        return x
2,956✔
1579
    elseif nf == 0
84,599✔
1580
        return ccall(:jl_new_struct_uninit, Any, (Any,), t)
48,185✔
1581
    else
1582
        na = nf
36,414✔
1583
        vflds = Vector{Any}(undef, nf)
36,414✔
1584
        for i in 1:nf
72,828✔
1585
            tag = Int32(read(s.io, UInt8)::UInt8)
74,811✔
1586
            if tag != UNDEFREF_TAG
74,811✔
1587
                f = handle_deserialize(s, tag)
74,810✔
1588
                na >= i && (vflds[i] = f)
74,808✔
1589
            else
1590
                na >= i && (na = i - 1) # rest of tail must be undefined values
1✔
1591
            end
1592
        end
113,206✔
1593
        return ccall(:jl_new_structv, Any, (Any, Ptr{Any}, UInt32), t, vflds, na)
36,412✔
1594
    end
1595
end
1596

1597
function deserialize_dict(s::AbstractSerializer, T::Type{<:AbstractDict})
5✔
1598
    n = read(s.io, Int32)
5✔
1599
    t = T(); sizehint!(t, n)
11✔
1600
    deserialize_cycle(s, t)
5✔
1601
    for i = 1:n
9✔
1602
        k = deserialize(s)
226✔
1603
        v = deserialize(s)
226✔
1604
        t[k] = v
226✔
1605
    end
448✔
1606
    return t
5✔
1607
end
1608

1609
function deserialize(s::AbstractSerializer, T::Type{Dict{K,V}}) where {K,V}
3✔
1610
    return deserialize_dict(s, T)
3✔
1611
end
1612

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

1615
function deserialize(s::AbstractSerializer, t::Type{Regex})
1✔
1616
    pattern = deserialize(s)
1✔
1617
    compile_options = deserialize(s)
1✔
1618
    match_options = deserialize(s)
1✔
1619
    return Regex(pattern, compile_options, match_options)
1✔
1620
end
1621

1622
## StackTraces
1623

1624
# provide a custom serializer that skips attempting to serialize the `outer_linfo`
1625
# which is likely to contain complex references, types, and module references
1626
# that may not exist on the receiver end
1627
function serialize(s::AbstractSerializer, frame::Base.StackTraces.StackFrame)
760✔
1628
    serialize_type(s, typeof(frame))
760✔
1629
    serialize(s, frame.func)
760✔
1630
    serialize(s, frame.file)
760✔
1631
    write(s.io, frame.line)
760✔
1632
    write(s.io, frame.from_c)
760✔
1633
    write(s.io, frame.inlined)
760✔
1634
    write(s.io, frame.pointer)
760✔
1635
    nothing
760✔
1636
end
1637

1638
function deserialize(s::AbstractSerializer, ::Type{Base.StackTraces.StackFrame})
760✔
1639
    func = deserialize(s)
760✔
1640
    file = deserialize(s)
760✔
1641
    line = read(s.io, Int)
760✔
1642
    from_c = read(s.io, Bool)
760✔
1643
    inlined = read(s.io, Bool)
760✔
1644
    pointer = read(s.io, UInt64)
760✔
1645
    return Base.StackTraces.StackFrame(func, file, line, nothing, from_c, inlined, pointer)
760✔
1646
end
1647

1648
function serialize(s::AbstractSerializer, lock::Base.AbstractLock)
18✔
1649
    # assert_havelock(lock)
1650
    serialize_cycle_header(s, lock)
35✔
1651
    nothing
18✔
1652
end
1653

1654
function deserialize(s::AbstractSerializer, ::Type{T}) where T<:Base.AbstractLock
17✔
1655
    lock = T()
17✔
1656
    deserialize_cycle(s, lock)
17✔
1657
    return lock
17✔
1658
end
1659

1660
function serialize(s::AbstractSerializer, cond::Base.GenericCondition)
2✔
1661
    serialize_cycle_header(s, cond) && return
4✔
1662
    serialize(s, cond.lock)
3✔
1663
    nothing
2✔
1664
end
1665

1666
function deserialize(s::AbstractSerializer, ::Type{T}) where T<:Base.GenericCondition
2✔
1667
    lock = deserialize(s)
2✔
1668
    cond = T(lock)
2✔
1669
    deserialize_cycle(s, cond)
2✔
1670
    return cond
2✔
1671
end
1672

1673
serialize(s::AbstractSerializer, l::LazyString) =
2✔
1674
    invoke(serialize, Tuple{AbstractSerializer,Any}, s, Base._LazyString((), string(l)))
1675

1676
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