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

JuliaLang / julia / #37745

11 Apr 2024 03:54AM UTC coverage: 87.241% (+5.8%) from 81.402%
#37745

push

local

web-flow
Fix comparison base for line table compression (#54032)

I'm not entirely sure what the original intent of this statement was,
but the effect ends up being that some codeloc entries end up negative
in the compressed representation, but the code always assumes unsigned
integers, so things roundtripped badly, leading to badly corrupted stack
traces. I guess this might have been a rebase mistake,
since the same line exists (correctly) a few lines prior. Fixes #54031.

75950 of 87058 relevant lines covered (87.24%)

15852930.37 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)
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 = 27 # 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)
62,563✔
92
    ptags = convert(Ptr{Ptr{Cvoid}}, pointer(TAGS))
62,563✔
93
    # note: constant ints & reserved slots never returned here
94
    @inbounds for i in 1:(NTAGS-(n_reserved_slots+2*n_int_literals))
3,420,467✔
95
        ptr == unsafe_load(ptags,i) && return i%Int32
6,855,401✔
96
    end
13,608,937✔
97
    return Int32(-1)
23,261✔
98
end
99
desertag(i::Int32) = @inbounds(TAGS[i])
232,990✔
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)
99,056✔
146

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

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

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

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

187
serialize(s::AbstractSerializer, x::Bool) = x ? writetag(s.io, TRUE_TAG) :
3,296✔
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,590✔
193

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

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

216
function serialize(s::AbstractSerializer, x::Symbol)
14,208✔
217
    tag = sertag(x)
2,218,085✔
218
    if tag > 0
14,208✔
219
        return write_as_tag(s.io, tag)
4,279✔
220
    end
221
    pname = unsafe_convert(Ptr{UInt8}, x)
9,929✔
222
    len = Int(ccall(:strlen, Csize_t, (Cstring,), pname))
9,929✔
223
    if len > 7
9,929✔
224
        serialize_cycle(s, x) && return
4,330✔
225
    end
226
    if len <= NTAGS
8,182✔
227
        writetag(s.io, SYMBOL_TAG)
8,441✔
228
        write(s.io, UInt8(len))
8,441✔
229
    else
230
        writetag(s.io, LONGSYMBOL_TAG)
5✔
231
        write(s.io, Int32(len))
4✔
232
    end
233
    unsafe_write(s.io, pname, len)
8,182✔
234
    nothing
235
end
236

237
function serialize_array_data(s::IO, a)
1✔
238
    require_one_based_indexing(a)
331✔
239
    isempty(a) && return 0
331✔
240
    if eltype(a) === Bool
327✔
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)
326✔
255
    end
256
end
257

258
function serialize(s::AbstractSerializer, a::Array)
1,604✔
259
    serialize_cycle(s, a) && return
1,604✔
260
    elty = eltype(a)
1,602✔
261
    writetag(s.io, ARRAY_TAG)
1,695✔
262
    if elty !== UInt8
1,602✔
263
        serialize(s, elty)
1,456✔
264
    end
265
    if ndims(a) != 1
1,602✔
266
        serialize(s, size(a))
19✔
267
    else
268
        serialize(s, length(a))
1,584✔
269
    end
270
    if isbitstype(elty)
1,602✔
271
        serialize_array_data(s.io, a)
318✔
272
    else
273
        sizehint!(s.table, div(length(a),4))  # prepare for lots of pointers
1,300✔
274
        @inbounds for i in eachindex(a)
1,284✔
275
            if isassigned(a, i)
46,838✔
276
                serialize(s, a[i])
69,870✔
277
            else
278
                writetag(s.io, UNDEFREF_TAG)
2✔
279
            end
280
        end
46,838✔
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,763✔
317
    len = sizeof(ss)
2,763✔
318
    if len > 7
2,763✔
319
        serialize_cycle(s, ss) && return
1,583✔
320
        writetag(s.io, SHARED_REF_TAG)
823✔
321
    end
322
    if len <= NTAGS
1,985✔
323
        writetag(s.io, STRING_TAG)
1,920✔
324
        write(s.io, UInt8(len))
1,920✔
325
    else
326
        writetag(s.io, LONGSTRING_TAG)
97✔
327
        write(s.io, Int64(len))
96✔
328
    end
329
    write(s.io, ss)
1,985✔
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)
945✔
352
    serialize_cycle(s, ex) && return
945✔
353
    l = length(ex.args)
945✔
354
    if l <= NTAGS
945✔
355
        writetag(s.io, EXPR_TAG)
1,263✔
356
        write(s.io, UInt8(l))
1,263✔
357
    else
358
        writetag(s.io, LONGEXPR_TAG)
2✔
359
        write(s.io, Int32(l))
1✔
360
    end
361
    serialize(s, ex.head)
945✔
362
    for a in ex.args
945✔
363
        serialize(s, a)
2,711✔
364
    end
2,711✔
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)
156✔
371
        serialize(s, v)
156✔
372
    end
156✔
373
end
374

375
function serialize(s::AbstractSerializer, d::Dict)
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)
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)
4,319✔
388
    p = parentmodule(m)
4,319✔
389
    if p === m || m === Base
5,320✔
390
        key = Base.root_module_key(m)
4,261✔
391
        uuid = key.uuid
4,261✔
392
        serialize(s, uuid === nothing ? nothing : uuid.value)
5,825✔
393
        serialize(s, Symbol(key.name))
4,261✔
394
    else
395
        serialize_mod_names(s, p)
58✔
396
        serialize(s, nameof(m))
58✔
397
    end
398
end
399

400
function serialize(s::AbstractSerializer, m::Module)
295✔
401
    writetag(s.io, MODULE_TAG)
4,416✔
402
    serialize_mod_names(s, m)
4,261✔
403
    writetag(s.io, EMPTYTUPLE_TAG)
4,261✔
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)
142✔
434
    serialize_cycle(s, meth) && return
142✔
435
    writetag(s.io, METHOD_TAG)
150✔
436
    write(s.io, object_number(s, meth))
283✔
437
    serialize(s, meth.module)
142✔
438
    serialize(s, meth.name)
142✔
439
    serialize(s, meth.file)
142✔
440
    serialize(s, meth.line)
142✔
441
    serialize(s, meth.sig)
142✔
442
    serialize(s, meth.slot_syms)
142✔
443
    serialize(s, meth.nargs)
142✔
444
    serialize(s, meth.isva)
276✔
445
    serialize(s, meth.is_for_opaque_closure)
276✔
446
    serialize(s, meth.nospecializeinfer)
276✔
447
    serialize(s, meth.constprop)
142✔
448
    serialize(s, meth.purity)
150✔
449
    if isdefined(meth, :source)
142✔
450
        serialize(s, Base._uncompressed_ast(meth))
142✔
451
    else
452
        serialize(s, nothing)
×
453
    end
454
    if isdefined(meth, :generator)
142✔
455
        serialize(s, meth.generator)
×
456
    else
457
        serialize(s, nothing)
142✔
458
    end
459
    if isdefined(meth, :recursion_relation)
142✔
460
        serialize(s, method.recursion_relation)
×
461
    else
462
        serialize(s, nothing)
142✔
463
    end
464
    if isdefined(meth, :external_mt)
142✔
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
    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)
2✔
487
    serialize_cycle(s, t) && return
2✔
488
    if istaskstarted(t) && !istaskdone(t)
2✔
489
        error("cannot serialize a running Task")
×
490
    end
491
    writetag(s.io, TASK_TAG)
4✔
492
    serialize(s, t.code)
2✔
493
    serialize(s, t.storage)
2✔
494
    serialize(s, t.state)
4✔
495
    if t._isexception && (stk = Base.current_exceptions(t); !isempty(stk))
2✔
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))
1✔
500
    else
501
        serialize(s, t.result)
1✔
502
    end
503
    serialize(s, t._isexception)
2✔
504
end
505

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

510
        v = getglobal(g.mod, g.name)
18✔
511
        unw = unwrap_unionall(v)
18✔
512
        if isa(unw,DataType) && v === unw.name.wrapper && should_send_whole_type(s, unw)
24✔
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)
6✔
516
            serialize(s, v)
5✔
517
            return
5✔
518
        end
519
    end
520
    writetag(s.io, GLOBALREF_TAG)
422✔
521
    serialize(s, g.mod)
410✔
522
    serialize(s, g.name)
410✔
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)
16✔
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)
142✔
533
    serialize(s, t.name)
142✔
534
    serialize(s, t.names)
142✔
535
    primary = unwrap_unionall(t.wrapper)
142✔
536
    serialize(s, primary.super)
142✔
537
    serialize(s, primary.parameters)
142✔
538
    serialize(s, primary.types)
142✔
539
    serialize(s, Base.issingletontype(primary))
269✔
540
    serialize(s, t.flags & 0x1 == 0x1) # .abstract
276✔
541
    serialize(s, t.flags & 0x2 == 0x2) # .mutable
276✔
542
    serialize(s, Int32(length(primary.types) - t.n_uninitialized))
142✔
543
    serialize(s, t.max_methods)
142✔
544
    if isdefined(t, :mt) && t.mt !== Symbol.name.mt
142✔
545
        serialize(s, t.mt.name)
141✔
546
        serialize(s, collect(Base.MethodList(t.mt)))
282✔
547
        serialize(s, t.mt.max_args)
141✔
548
        kws = collect(methods(Core.kwcall, (Any, t.wrapper, Vararg)))
142✔
549
        if isempty(kws)
141✔
550
            writetag(s.io, UNDEFREF_TAG)
140✔
551
        else
552
            serialize(s, kws)
1✔
553
        end
554
    else
555
        writetag(s.io, UNDEFREF_TAG)
1✔
556
    end
557
    nothing
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)
562
    tn = t.name
6,092✔
563
    if isdefined(tn, :mt)
6,092✔
564
        # TODO improve somehow
565
        # send whole type for anonymous functions in Main
566
        name = tn.mt.name
5,950✔
567
        mod = tn.module
5,950✔
568
        isanonfunction = mod === Main && # only Main
5,951✔
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
11,900✔
576
    end
577
    return false
142✔
578
end
579

580
function serialize_type_data(s, @nospecialize(t::DataType))
6,086✔
581
    whole = should_send_whole_type(s, t)
12,030✔
582
    iswrapper = (t === unwrap_unionall(t.name.wrapper))
6,086✔
583
    if whole && iswrapper
6,086✔
584
        writetag(s.io, WRAPPER_DATATYPE_TAG)
175✔
585
        serialize(s, t.name)
158✔
586
        return
158✔
587
    end
588
    serialize_cycle(s, t) && return
5,928✔
589
    if whole
3,913✔
590
        writetag(s.io, FULL_DATATYPE_TAG)
232✔
591
        serialize(s, t.name)
230✔
592
    else
593
        writetag(s.io, DATATYPE_TAG)
3,817✔
594
        serialize(s, nameof(t))
3,683✔
595
        serialize(s, parentmodule(t))
3,683✔
596
    end
597
    if !isempty(t.parameters)
3,913✔
598
        if iswrapper
1,818✔
599
            write(s.io, Int32(0))
4✔
600
        else
601
            write(s.io, Int32(length(t.parameters)))
1,814✔
602
            for p in t.parameters
3,628✔
603
                serialize(s, p)
4,805✔
604
            end
4,805✔
605
        end
606
    end
607
    nothing
608
end
609

610
function serialize(s::AbstractSerializer, t::DataType)
5,698✔
611
    tag = sertag(t)
458,857✔
612
    tag > 0 && return write_as_tag(s.io, tag)
5,698✔
613
    if t === Tuple
1,784✔
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)
1,784✔
621
end
622

623
function serialize_type(s::AbstractSerializer, @nospecialize(t::DataType), ref::Bool = false)
7,244✔
624
    tag = sertag(t)
801,110✔
625
    tag > 0 && return writetag(s.io, tag)
7,230✔
626
    writetag(s.io, ref ? REF_OBJECT_TAG : OBJECT_TAG)
4,405✔
627
    serialize_type_data(s, t)
4,300✔
628
end
629

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

640
function serialize(s::AbstractSerializer, n::Int64)
8,893✔
641
    if 0 <= n <= (n_int_literals-1)
8,893✔
642
        write(s.io, UInt8(ZERO64_TAG+n))
5,123✔
643
    elseif typemin(Int32) <= n <= typemax(Int32)
3,770✔
644
        writetag(s.io, SHORTINT64_TAG)
3,623✔
645
        write(s.io, Int32(n))
3,609✔
646
    else
647
        writetag(s.io, INT64_TAG)
162✔
648
        write(s.io, n)
161✔
649
    end
650
    nothing
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)
48,283✔
658
end
659

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

662
function serialize(s::AbstractSerializer, u::UnionAll)
138✔
663
    writetag(s.io, UNIONALL_TAG)
149✔
664
    n = 0; t = u
138✔
665
    while isa(t, UnionAll)
404✔
666
        t = t.body
266✔
667
        n += 1
266✔
668
    end
266✔
669
    if isa(t, DataType) && t === unwrap_unionall(t.name.wrapper)
138✔
670
        write(s.io, UInt8(1))
145✔
671
        write(s.io, Int16(n))
136✔
672
        serialize(s, t)
136✔
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)
35,406✔
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))
35,418✔
688
    tag = sertag(x)
3,400,428✔
689
    if tag > 0
35,418✔
690
        return write_as_tag(s.io, tag)
28,170✔
691
    end
692
    t = typeof(x)::DataType
7,248✔
693
    if isprimitivetype(t)
7,248✔
694
        serialize_type(s, t)
12✔
695
        write(s.io, x)
12✔
696
    else
697
        if ismutable(x)
7,236✔
698
            serialize_cycle(s, x) && return
703✔
699
            serialize_type(s, t, true)
437✔
700
        else
701
            serialize_type(s, t, false)
6,533✔
702
        end
703
        nf = nfields(x)
6,970✔
704
        for i in 1:nf
6,970✔
705
            if isdefined(x, i)
20,588✔
706
                serialize(s, getfield(x, i))
20,587✔
707
            else
708
                writetag(s.io, UNDEFREF_TAG)
1✔
709
            end
710
        end
20,588✔
711
    end
712
    nothing
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)
213✔
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
115✔
743
    nothing
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)
65✔
805
    ss = Serializer(s)
115✔
806
    writeheader(ss)
115✔
807
    serialize(ss, x)
115✔
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)
434,454✔
844
    handle_deserialize(s, Int32(read(s.io, UInt8)::UInt8))
450,944✔
845
end
846

847
function deserialize_cycle(s::AbstractSerializer, @nospecialize(x))
52✔
848
    slot = pop!(s.pending_refs)
52✔
849
    s.table[slot] = x
52✔
850
    nothing
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))
45,040✔
859
    s.table[s.counter] = x
45,040✔
860
    s.counter += 1
45,040✔
861
    nothing
862
end
863

864
function gettable(s::AbstractSerializer, id::Int)
865
    get(s.table, id) do
26,776✔
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)
569,207✔
881
    if b == 0
569,207✔
882
        return desertag(Int32(read(s.io, UInt8)::UInt8))
18,589✔
883
    end
884
    if b >= VALUE_TAGS
550,618✔
885
        return desertag(b)
214,086✔
886
    elseif b == TUPLE_TAG
336,532✔
887
        return deserialize_tuple(s, Int(read(s.io, UInt8)::UInt8))
36,904✔
888
    elseif b == SHORTBACKREF_TAG
299,628✔
889
        id = read(s.io, UInt16)::UInt16
26,776✔
890
        return gettable(s, Int(id))
26,776✔
891
    elseif b == BACKREF_TAG
272,852✔
892
        id = read(s.io, Int32)::Int32
×
893
        return gettable(s, Int(id))
×
894
    elseif b == ARRAY_TAG
272,852✔
895
        return deserialize_array(s)
3,518✔
896
    elseif b == DATATYPE_TAG
269,334✔
897
        return deserialize_datatype(s, false)
45,576✔
898
    elseif b == FULL_DATATYPE_TAG
223,758✔
899
        return deserialize_datatype(s, true)
2✔
900
    elseif b == WRAPPER_DATATYPE_TAG
223,756✔
901
        tname = deserialize(s)::Core.TypeName
19✔
902
        return unwrap_unionall(tname.wrapper)
19✔
903
    elseif b == OBJECT_TAG
223,737✔
904
        t = deserialize(s)
45,532✔
905
        if t === Missing
45,532✔
906
            return missing
×
907
        end
908
        return deserialize(s, t)
45,532✔
909
    elseif b == REF_OBJECT_TAG
178,205✔
910
        slot = s.counter; s.counter += 1
17✔
911
        push!(s.pending_refs, slot)
17✔
912
        t = deserialize(s)
17✔
913
        return deserialize(s, t)
17✔
914
    elseif b == SHARED_REF_TAG
178,188✔
915
        slot = s.counter; s.counter += 1
873✔
916
        obj = deserialize(s)
873✔
917
        s.table[slot] = obj
873✔
918
        return obj
873✔
919
    elseif b == SYMBOL_TAG
177,315✔
920
        return deserialize_symbol(s, Int(read(s.io, UInt8)::UInt8))
61,394✔
921
    elseif b == SHORTINT64_TAG
115,921✔
922
        return Int64(read(s.io, Int32)::Int32)
29,872✔
923
    elseif b == EXPR_TAG
86,049✔
924
        return deserialize_expr(s, Int(read(s.io, UInt8)::UInt8))
1,042✔
925
    elseif b == MODULE_TAG
85,007✔
926
        return deserialize_module(s)
45,740✔
927
    elseif b == STRING_TAG
39,267✔
928
        return deserialize_string(s, Int(read(s.io, UInt8)::UInt8))
1,216✔
929
    elseif b == LONGSTRING_TAG
38,051✔
930
        return deserialize_string(s, Int(read(s.io, Int64)::Int64))
1✔
931
    elseif b == SIMPLEVECTOR_TAG
38,050✔
932
        return deserialize_svec(s)
36✔
933
    elseif b == GLOBALREF_TAG
38,014✔
934
        return GlobalRef(deserialize(s)::Module, deserialize(s)::Symbol)
14✔
935
    elseif b == FULL_GLOBALREF_TAG
38,000✔
936
        ty = deserialize(s)
1✔
937
        tn = unwrap_unionall(ty).name
1✔
938
        return GlobalRef(tn.module, tn.name)
1✔
939
    elseif b == LONGTUPLE_TAG
37,999✔
940
        return deserialize_tuple(s, Int(read(s.io, Int32)::Int32))
1✔
941
    elseif b == LONGEXPR_TAG
37,998✔
942
        return deserialize_expr(s, Int(read(s.io, Int32)::Int32))
1✔
943
    elseif b == LONGBACKREF_TAG
37,997✔
944
        id = read(s.io, Int64)::Int64
×
945
        return gettable(s, Int(id))
×
946
    elseif b == LONGSYMBOL_TAG
37,997✔
947
        return deserialize_symbol(s, Int(read(s.io, Int32)::Int32))
4✔
948
    elseif b == HEADER_TAG
37,993✔
949
        readheader(s)
105✔
950
        return deserialize(s)
101✔
951
    elseif b == INT8_TAG
37,888✔
952
        return read(s.io, Int8)
12✔
953
    elseif b == INT8_TAG+1
37,876✔
954
        return read(s.io, UInt8)
296✔
955
    elseif b == INT8_TAG+2
37,580✔
956
        return read(s.io, Int16)
4✔
957
    elseif b == INT8_TAG+3
37,576✔
958
        return read(s.io, UInt16)
28✔
959
    elseif b == INT32_TAG
37,548✔
960
        return read(s.io, Int32)
8✔
961
    elseif b == INT8_TAG+5
37,540✔
962
        return read(s.io, UInt32)
6✔
963
    elseif b == INT64_TAG
37,534✔
964
        return read(s.io, Int64)
1✔
965
    elseif b == INT8_TAG+7
37,533✔
966
        return read(s.io, UInt64)
171✔
967
    elseif b == INT8_TAG+8
37,362✔
968
        return read(s.io, Int128)
11,074✔
969
    elseif b == INT8_TAG+9
26,288✔
970
        return read(s.io, UInt128)
14,864✔
971
    elseif b == INT8_TAG+10
11,424✔
972
        return read(s.io, Float16)
4✔
973
    elseif b == INT8_TAG+11
11,420✔
974
        return read(s.io, Float32)
×
975
    elseif b == INT8_TAG+12
11,420✔
976
        return read(s.io, Float64)
×
977
    elseif b == INT8_TAG+13
11,420✔
978
        return read(s.io, Char)
11,103✔
979
    elseif b == IDDICT_TAG
317✔
980
        slot = s.counter; s.counter += 1
2✔
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
315✔
986
    if ismutabletype(t) && length(t.types) > 0  # manual specialization of fieldcount
315✔
987
        slot = s.counter; s.counter += 1
33✔
988
        push!(s.pending_refs, slot)
33✔
989
    end
990
    return deserialize(s, t)
315✔
991
end
992

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

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

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

1010
function deserialize_module(s::AbstractSerializer)
45,740✔
1011
    mkey = deserialize(s)
45,740✔
1012
    if isa(mkey, Tuple)
45,740✔
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)
45,740✔
1023
        pkg = (mkey === nothing) ? Base.PkgId(name) : Base.PkgId(Base.UUID(mkey), name)
60,106✔
1024
        m = Base.root_module(pkg)
45,740✔
1025
        mname = deserialize(s)
45,740✔
1026
        while mname !== ()
45,798✔
1027
            m = getglobal(m, mname)::Module
58✔
1028
            mname = deserialize(s)
58✔
1029
        end
58✔
1030
    end
1031
    return m
45,740✔
1032
end
1033

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

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

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

1157

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

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

1291
const NullDebugInfo = DebugInfo(:none)
1292

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

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

1348
function deserialize_fillarray!(A::Union{Array{T},Memory{T}}, s::AbstractSerializer) where {T}
495✔
1349
    for i = eachindex(A)
495✔
1350
        tag = Int32(read(s.io, UInt8)::UInt8)
55,975✔
1351
        if tag != UNDEFREF_TAG
55,975✔
1352
            @inbounds A[i] = handle_deserialize(s, tag)
55,973✔
1353
        end
1354
    end
111,458✔
1355
    return A
495✔
1356
end
1357

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

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

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

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

1408
module __deserialized_types__ end
1409

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

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

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

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

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

1497
function deserialize_datatype(s::AbstractSerializer, full::Bool)
45,578✔
1498
    slot = s.counter; s.counter += 1
45,578✔
1499
    if full
45,578✔
1500
        tname = deserialize(s)::Core.TypeName
2✔
1501
        ty = tname.wrapper
2✔
1502
    else
1503
        name = deserialize(s)::Symbol
45,576✔
1504
        mod = deserialize(s)::Module
45,576✔
1505
        ty = getglobal(mod, name)
45,576✔
1506
    end
1507
    if isa(ty,DataType) && isempty(ty.parameters)
45,578✔
1508
        t = ty
15,235✔
1509
    else
1510
        np = Int(read(s.io, Int32)::Int32)
30,343✔
1511
        if np == 0
30,343✔
1512
            t = unwrap_unionall(ty)
4✔
1513
        elseif ty === Tuple
30,339✔
1514
            # note np==0 has its own tag
1515
            if np == 1
470✔
1516
                t = Tuple{deserialize(s)}
461✔
1517
            elseif np == 2
9✔
1518
                t = Tuple{deserialize(s), deserialize(s)}
6✔
1519
            elseif np == 3
3✔
1520
                t = Tuple{deserialize(s), deserialize(s), deserialize(s)}
3✔
1521
            elseif np == 4
×
1522
                t = Tuple{deserialize(s), deserialize(s), deserialize(s), deserialize(s)}
×
1523
            else
1524
                t = Tuple{Any[ deserialize(s) for i=1:np ]...}
×
1525
            end
1526
        else
1527
            t = ty
29,869✔
1528
            for i = 1:np
29,869✔
1529
                t = t{deserialize(s)}
88,997✔
1530
            end
88,997✔
1531
        end
1532
    end
1533
    s.table[slot] = t
45,578✔
1534
    return t
45,578✔
1535
end
1536

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

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

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

1596
# default DataType deserializer
1597
function deserialize(s::AbstractSerializer, t::DataType)
45,603✔
1598
    nf = length(t.types)
45,603✔
1599
    if isprimitivetype(t)
45,603✔
1600
        return read(s.io, t)
12✔
1601
    elseif ismutabletype(t)
45,591✔
1602
        x = ccall(:jl_new_struct_uninit, Any, (Any,), t)
15✔
1603
        deserialize_cycle(s, x)
15✔
1604
        for i in 1:nf
15✔
1605
            tag = Int32(read(s.io, UInt8)::UInt8)
30✔
1606
            if tag != UNDEFREF_TAG
30✔
1607
                ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), x, i-1, handle_deserialize(s, tag))
30✔
1608
            end
1609
        end
47✔
1610
        return x
15✔
1611
    elseif nf == 0
45,576✔
1612
        return ccall(:jl_new_struct_uninit, Any, (Any,), t)
29,072✔
1613
    else
1614
        na = nf
16,504✔
1615
        vflds = Vector{Any}(undef, nf)
33,008✔
1616
        for i in 1:nf
16,504✔
1617
            tag = Int32(read(s.io, UInt8)::UInt8)
32,049✔
1618
            if tag != UNDEFREF_TAG
32,049✔
1619
                f = handle_deserialize(s, tag)
32,048✔
1620
                na >= i && (vflds[i] = f)
32,048✔
1621
            else
1622
                na >= i && (na = i - 1) # rest of tail must be undefined values
1✔
1623
            end
1624
        end
47,594✔
1625
        return ccall(:jl_new_structv, Any, (Any, Ptr{Any}, UInt32), t, vflds, na)
16,504✔
1626
    end
1627
end
1628

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

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

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

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

1654
## StackTraces
1655

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

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

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

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

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

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

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

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

© 2025 Coveralls, Inc