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

JuliaLang / julia / #38162

06 Aug 2025 08:25PM UTC coverage: 25.688% (-43.6%) from 69.336%
#38162

push

local

web-flow
fix runtime cglobal builtin function implementation (#59210)

This had failed to be updated for the LazyLibrary changes to codegen.

12976 of 50513 relevant lines covered (25.69%)

676965.51 hits per line

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

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

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

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

16
export serialize, deserialize, AbstractSerializer, Serializer
17

18
abstract type AbstractSerializer end
19

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

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

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

34
## serializing values ##
35

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

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

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

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

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

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

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

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

88
format_version(::AbstractSerializer) = ser_version
×
89
format_version(s::Serializer) = s.version
×
90

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

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

148
writetag(s::IO, tag) = (write(s, UInt8(tag)); nothing)
11,882✔
149

150
function write_as_tag(s::IO, tag)
151
    tag < VALUE_TAGS && write(s, UInt8(0))
114✔
152
    write(s, UInt8(tag))
114✔
153
    nothing
114✔
154
end
155

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

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

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

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

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

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

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

211
function serialize(s::AbstractSerializer, v::SimpleVector)
×
212
    writetag(s.io, SIMPLEVECTOR_TAG)
×
213
    write(s.io, Int32(length(v)))
×
214
    for x in v
×
215
        serialize(s, x)
×
216
    end
×
217
end
218

219
function serialize(s::AbstractSerializer, x::Symbol)
74✔
220
    tag = sertag(x)
12,014✔
221
    if tag > 0
74✔
222
        return write_as_tag(s.io, tag)
30✔
223
    end
224
    pname = unsafe_convert(Ptr{UInt8}, x)
44✔
225
    len = Int(ccall(:strlen, Csize_t, (Cstring,), pname))
44✔
226
    if len > 7
44✔
227
        serialize_cycle(s, x) && return
25✔
228
    end
229
    if len <= NTAGS
44✔
230
        writetag(s.io, SYMBOL_TAG)
44✔
231
        write(s.io, UInt8(len))
44✔
232
    else
233
        writetag(s.io, LONGSYMBOL_TAG)
×
234
        write(s.io, Int32(len))
×
235
    end
236
    unsafe_write(s.io, pname, len)
44✔
237
    nothing
44✔
238
end
239

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

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

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

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

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

319
function serialize(s::AbstractSerializer, ss::String)
7,370✔
320
    len = sizeof(ss)
7,370✔
321
    if len > 7
7,370✔
322
        serialize_cycle(s, ss) && return
3,596✔
323
        writetag(s.io, SHARED_REF_TAG)
850✔
324
    end
325
    if len <= NTAGS
4,624✔
326
        writetag(s.io, STRING_TAG)
4,622✔
327
        write(s.io, UInt8(len))
4,622✔
328
    else
329
        writetag(s.io, LONGSTRING_TAG)
2✔
330
        write(s.io, Int64(len))
2✔
331
    end
332
    write(s.io, ss)
4,624✔
333
    nothing
4,624✔
334
end
335

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

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

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

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

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

378
function serialize(s::AbstractSerializer, d::Dict)
832✔
379
    serialize_cycle_header(s, d) && return
1,910✔
380
    serialize_dict_data(s, d)
661✔
381
end
382

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

390
function serialize_mod_names(s::AbstractSerializer, m::Module)
36✔
391
    p = parentmodule(m)
36✔
392
    if p === m || m === Base
58✔
393
        key = Base.root_module_key(m)
34✔
394
        uuid = key.uuid
34✔
395
        serialize(s, uuid === nothing ? nothing : uuid.value)
38✔
396
        serialize(s, Symbol(key.name))
34✔
397
    else
398
        serialize_mod_names(s, p)
2✔
399
        serialize(s, nameof(m))
2✔
400
    end
401
end
402

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

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

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

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

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

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

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

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

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

484

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

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

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

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

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

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

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

587
function serialize_type_data(s, @nospecialize(t::DataType))
1,123✔
588
    whole = should_send_whole_type(s, t)
2,246✔
589
    iswrapper = (t === unwrap_unionall(t.name.wrapper))
1,123✔
590
    if whole && iswrapper
1,123✔
591
        writetag(s.io, WRAPPER_DATATYPE_TAG)
×
592
        serialize(s, t.name)
×
593
        return
×
594
    end
595
    serialize_cycle(s, t) && return
1,123✔
596
    if whole
34✔
597
        writetag(s.io, FULL_DATATYPE_TAG)
×
598
        serialize(s, t.name)
×
599
    else
600
        writetag(s.io, DATATYPE_TAG)
34✔
601
        serialize(s, nameof(t))
34✔
602
        serialize(s, parentmodule(t))
34✔
603
    end
604
    if !isempty(t.parameters)
34✔
605
        if iswrapper
23✔
606
            write(s.io, Int32(0))
×
607
        else
608
            write(s.io, Int32(length(t.parameters)))
23✔
609
            for p in t.parameters
46✔
610
                serialize(s, p)
65✔
611
            end
65✔
612
        end
613
    end
614
    nothing
34✔
615
end
616

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

630
function serialize_type(s::AbstractSerializer, @nospecialize(t::DataType), ref::Bool = false)
1,110✔
631
    tag = sertag(t)
184,260✔
632
    tag > 0 && return writetag(s.io, tag)
1,110✔
633
    writetag(s.io, ref ? REF_OBJECT_TAG : OBJECT_TAG)
1,110✔
634
    serialize_type_data(s, t)
1,110✔
635
end
636

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

647
function serialize(s::AbstractSerializer, n::Int64)
36✔
648
    if 0 <= n <= (n_int_literals-1)
36✔
649
        write(s.io, UInt8(ZERO64_TAG+n))
26✔
650
    elseif typemin(Int32) <= n <= typemax(Int32)
10✔
651
        writetag(s.io, SHORTINT64_TAG)
10✔
652
        write(s.io, Int32(n))
10✔
653
    else
654
        writetag(s.io, INT64_TAG)
×
655
        write(s.io, n)
×
656
    end
657
    nothing
36✔
658
end
659

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

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

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

687
serialize(s::AbstractSerializer, @nospecialize(x)) = serialize_any(s, x)
476✔
688

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

694
function serialize_any(s::AbstractSerializer, @nospecialize(x))
479✔
695
    tag = sertag(x)
76,874✔
696
    if tag > 0
479✔
697
        return write_as_tag(s.io, tag)
30✔
698
    end
699
    t = typeof(x)::DataType
449✔
700
    if isprimitivetype(t)
449✔
701
        serialize_type(s, t)
×
702
        write(s.io, x)
×
703
    else
704
        if ismutable(x)
449✔
705
            serialize_cycle(s, x) && return
×
706
            serialize_type(s, t, true)
×
707
        else
708
            serialize_type(s, t, false)
449✔
709
        end
710
        nf = nfields(x)
449✔
711
        for i in 1:nf
449✔
712
            if isdefined(x, i)
445✔
713
                serialize(s, getfield(x, i))
445✔
714
            else
715
                writetag(s.io, UNDEFREF_TAG)
×
716
            end
717
        end
445✔
718
    end
719
    nothing
449✔
720
end
721

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

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

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

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

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

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

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

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

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

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

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

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

827
## deserializing values ##
828

829
"""
830
    deserialize(stream)
831

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

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

843
Open a file and deserialize its contents.
844

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

850
function deserialize(s::AbstractSerializer)
2,234✔
851
    handle_deserialize(s, Int32(read(s.io, UInt8)::UInt8))
11,115✔
852
end
853

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

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

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

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

884
# deserialize_ is an internal function to dispatch on the tag
885
# describing the serialized representation. the number of
886
# representations is fixed, so deserialize_ does not get extended.
887
function handle_deserialize(s::AbstractSerializer, b::Int32)
12,022✔
888
    if b == 0
12,022✔
889
        return desertag(Int32(read(s.io, UInt8)::UInt8))
18✔
890
    end
891
    if b >= VALUE_TAGS
12,004✔
892
        return desertag(b)
190✔
893
    elseif b == TUPLE_TAG
11,814✔
894
        return deserialize_tuple(s, Int(read(s.io, UInt8)::UInt8))
8✔
895
    elseif b == SHORTBACKREF_TAG
11,806✔
896
        id = read(s.io, UInt16)::UInt16
4,423✔
897
        return gettable(s, Int(id))
4,423✔
898
    elseif b == BACKREF_TAG
7,383✔
899
        id = read(s.io, Int32)::Int32
×
900
        return gettable(s, Int(id))
×
901
    elseif b == ARRAY_TAG
7,383✔
902
        return deserialize_array(s)
12✔
903
    elseif b == DATATYPE_TAG
7,371✔
904
        return deserialize_datatype(s, false)
34✔
905
    elseif b == FULL_DATATYPE_TAG
7,337✔
906
        return deserialize_datatype(s, true)
×
907
    elseif b == WRAPPER_DATATYPE_TAG
7,337✔
908
        tname = deserialize(s)::Core.TypeName
×
909
        return unwrap_unionall(tname.wrapper)
×
910
    elseif b == OBJECT_TAG
7,337✔
911
        t = deserialize(s)
449✔
912
        if t === Missing
449✔
913
            return missing
×
914
        end
915
        return deserialize(s, t)
449✔
916
    elseif b == REF_OBJECT_TAG
6,888✔
917
        slot = s.counter; s.counter += 1
661✔
918
        push!(s.pending_refs, slot)
661✔
919
        t = deserialize(s)
661✔
920
        return deserialize(s, t)
661✔
921
    elseif b == SHARED_REF_TAG
6,227✔
922
        slot = s.counter; s.counter += 1
850✔
923
        obj = deserialize(s)
850✔
924
        s.table[slot] = obj
850✔
925
        return obj
850✔
926
    elseif b == SYMBOL_TAG
5,377✔
927
        return deserialize_symbol(s, Int(read(s.io, UInt8)::UInt8))
44✔
928
    elseif b == SHORTINT64_TAG
5,333✔
929
        return Int64(read(s.io, Int32)::Int32)
10✔
930
    elseif b == EXPR_TAG
5,323✔
931
        return deserialize_expr(s, Int(read(s.io, UInt8)::UInt8))
×
932
    elseif b == MODULE_TAG
5,323✔
933
        return deserialize_module(s)
34✔
934
    elseif b == STRING_TAG
5,289✔
935
        return deserialize_string(s, Int(read(s.io, UInt8)::UInt8))
4,622✔
936
    elseif b == LONGSTRING_TAG
667✔
937
        return deserialize_string(s, Int(read(s.io, Int64)::Int64))
2✔
938
    elseif b == SIMPLEVECTOR_TAG
665✔
939
        return deserialize_svec(s)
×
940
    elseif b == GLOBALREF_TAG
665✔
941
        return GlobalRef(deserialize(s)::Module, deserialize(s)::Symbol)
×
942
    elseif b == FULL_GLOBALREF_TAG
665✔
943
        ty = deserialize(s)
×
944
        tn = unwrap_unionall(ty).name
×
945
        return GlobalRef(tn.module, tn.name)
×
946
    elseif b == LONGTUPLE_TAG
665✔
947
        return deserialize_tuple(s, Int(read(s.io, Int32)::Int32))
×
948
    elseif b == LONGEXPR_TAG
665✔
949
        return deserialize_expr(s, Int(read(s.io, Int32)::Int32))
×
950
    elseif b == LONGBACKREF_TAG
665✔
951
        id = read(s.io, Int64)::Int64
×
952
        return gettable(s, Int(id))
×
953
    elseif b == LONGSYMBOL_TAG
665✔
954
        return deserialize_symbol(s, Int(read(s.io, Int32)::Int32))
×
955
    elseif b == HEADER_TAG
665✔
956
        readheader(s)
1✔
957
        return deserialize(s)
1✔
958
    elseif b == INT8_TAG
664✔
959
        return read(s.io, Int8)
×
960
    elseif b == INT8_TAG+1
664✔
961
        return read(s.io, UInt8)
×
962
    elseif b == INT8_TAG+2
664✔
963
        return read(s.io, Int16)
×
964
    elseif b == INT8_TAG+3
664✔
965
        return read(s.io, UInt16)
×
966
    elseif b == INT32_TAG
664✔
967
        return read(s.io, Int32)
×
968
    elseif b == INT8_TAG+5
664✔
969
        return read(s.io, UInt32)
×
970
    elseif b == INT64_TAG
664✔
971
        return read(s.io, Int64)
×
972
    elseif b == INT8_TAG+7
664✔
973
        return read(s.io, UInt64)
×
974
    elseif b == INT8_TAG+8
664✔
975
        return read(s.io, Int128)
×
976
    elseif b == INT8_TAG+9
664✔
977
        return read(s.io, UInt128)
420✔
978
    elseif b == INT8_TAG+10
244✔
979
        return read(s.io, Float16)
×
980
    elseif b == INT8_TAG+11
244✔
981
        return read(s.io, Float32)
×
982
    elseif b == INT8_TAG+12
244✔
983
        return read(s.io, Float64)
244✔
984
    elseif b == INT8_TAG+13
×
985
        return read(s.io, Char)
×
986
    elseif b == IDDICT_TAG
×
987
        slot = s.counter; s.counter += 1
×
988
        push!(s.pending_refs, slot)
×
989
        t = deserialize(s)
×
990
        return deserialize_dict(s, t)
×
991
    end
992
    t = desertag(b)::DataType
×
993
    if ismutabletype(t) && length(t.types) > 0  # manual specialization of fieldcount
×
994
        slot = s.counter; s.counter += 1
×
995
        push!(s.pending_refs, slot)
×
996
    end
997
    return deserialize(s, t)
×
998
end
999

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

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

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

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

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

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

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

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

1183

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

1193
# v1.12 disallows bare symbols in IR, but older CodeInfos might still have them
1194
function symbol_to_globalref(@nospecialize(x), m::Module)
×
1195
    mapper(@nospecialize(x)) = symbol_to_globalref(x, m)
×
1196
    if x isa Symbol
×
1197
        return GlobalRef(m, x)
×
1198
    elseif x isa Expr
×
1199
        return Expr(x.head, map(mapper, x.args)...)
×
1200
    elseif x isa ReturnNode
×
1201
        return ReturnNode(mapper(x.val))
×
1202
    elseif x isa GotoIfNot
×
1203
        return GotoIfNot(mapper(x.cond), x.dest)
×
1204
    else
1205
        return x
×
1206
    end
1207
end
1208

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

1343
import Core: NullDebugInfo
1344

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

1351
function deserialize_array(s::AbstractSerializer)
12✔
1352
    slot = s.counter; s.counter += 1
12✔
1353
    d1 = deserialize(s)
12✔
1354
    if isa(d1, Type)
12✔
1355
        elty = d1
12✔
1356
        d1 = deserialize(s)
12✔
1357
    else
1358
        elty = UInt8
×
1359
    end
1360
    if isa(d1, Int32) || isa(d1, Int64)
24✔
1361
        if elty !== Bool && isbitstype(elty)
12✔
1362
            a = Vector{elty}(undef, d1)
4✔
1363
            s.table[slot] = a
4✔
1364
            return read!(s.io, a)
4✔
1365
        end
1366
        dims = (Int(d1),)
16✔
1367
    elseif d1 isa Dims
×
1368
        dims = d1::Dims
×
1369
    else
1370
        dims = convert(Dims, d1::Tuple{Vararg{OtherInt}})::Dims
×
1371
    end
1372
    if isbitstype(elty)
8✔
1373
        n = prod(dims)::Int
×
1374
        if elty === Bool && n > 0
×
1375
            A = Array{Bool, length(dims)}(undef, dims)
×
1376
            i = 1
×
1377
            while i <= n
×
1378
                b = read(s.io, UInt8)::UInt8
×
1379
                v = (b >> 7) != 0
×
1380
                count = b & 0x7f
×
1381
                nxt = i + count
×
1382
                while i < nxt
×
1383
                    A[i] = v
×
1384
                    i += 1
×
1385
                end
×
1386
            end
×
1387
        else
1388
            A = read!(s.io, Array{elty}(undef, dims))
×
1389
        end
1390
        s.table[slot] = A
×
1391
        return A
×
1392
    end
1393
    A = Array{elty, length(dims)}(undef, dims)
8✔
1394
    s.table[slot] = A
8✔
1395
    sizehint!(s.table, s.counter + div(length(A)::Int,4))
9✔
1396
    deserialize_fillarray!(A, s)
8✔
1397
    return A
8✔
1398
end
1399

1400
function deserialize_fillarray!(A::Union{Array{T},Memory{T}}, s::AbstractSerializer) where {T}
8✔
1401
    for i = eachindex(A)
8✔
1402
        tag = Int32(read(s.io, UInt8)::UInt8)
422✔
1403
        if tag != UNDEFREF_TAG
422✔
1404
            @inbounds A[i] = handle_deserialize(s, tag)
422✔
1405
        end
1406
    end
839✔
1407
    return A
8✔
1408
end
1409

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

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

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

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

1460
module __deserialized_types__ end
1461

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

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

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

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

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

1536
function deserialize_datatype(s::AbstractSerializer, full::Bool)
34✔
1537
    slot = s.counter; s.counter += 1
34✔
1538
    if full
34✔
1539
        tname = deserialize(s)::Core.TypeName
×
1540
        ty = tname.wrapper
×
1541
    else
1542
        name = deserialize(s)::Symbol
34✔
1543
        mod = deserialize(s)::Module
34✔
1544
        ty = getglobal(mod, name)
34✔
1545
    end
1546
    if isa(ty,DataType) && isempty(ty.parameters)
34✔
1547
        t = ty
11✔
1548
    else
1549
        np = Int(read(s.io, Int32)::Int32)
23✔
1550
        if np == 0
23✔
1551
            t = unwrap_unionall(ty)
×
1552
        elseif ty === Tuple
23✔
1553
            # note np==0 has its own tag
1554
            if np == 1
×
1555
                t = Tuple{deserialize(s)}
×
1556
            elseif np == 2
×
1557
                t = Tuple{deserialize(s), deserialize(s)}
×
1558
            elseif np == 3
×
1559
                t = Tuple{deserialize(s), deserialize(s), deserialize(s)}
×
1560
            elseif np == 4
×
1561
                t = Tuple{deserialize(s), deserialize(s), deserialize(s), deserialize(s)}
×
1562
            else
1563
                t = Tuple{Any[ deserialize(s) for i=1:np ]...}
×
1564
            end
1565
        else
1566
            t = ty
23✔
1567
            for i = 1:np
23✔
1568
                t = t{deserialize(s)}
65✔
1569
            end
65✔
1570
        end
1571
    end
1572
    s.table[slot] = t
34✔
1573
    return t
34✔
1574
end
1575

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

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

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

1635
# default DataType deserializer
1636
function deserialize(s::AbstractSerializer, t::DataType)
449✔
1637
    nf = length(t.types)
449✔
1638
    if isprimitivetype(t)
449✔
1639
        return read(s.io, t)
×
1640
    elseif ismutabletype(t)
449✔
1641
        x = ccall(:jl_new_struct_uninit, Any, (Any,), t)
×
1642
        deserialize_cycle(s, x)
×
1643
        for i in 1:nf
×
1644
            tag = Int32(read(s.io, UInt8)::UInt8)
×
1645
            if tag != UNDEFREF_TAG
×
1646
                ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), x, i-1, handle_deserialize(s, tag))
×
1647
            end
1648
        end
×
1649
        return x
×
1650
    elseif nf == 0
449✔
1651
        return ccall(:jl_new_struct_uninit, Any, (Any,), t)
20✔
1652
    else
1653
        na = nf
429✔
1654
        vflds = Vector{Any}(undef, nf)
429✔
1655
        for i in 1:nf
429✔
1656
            tag = Int32(read(s.io, UInt8)::UInt8)
445✔
1657
            if tag != UNDEFREF_TAG
445✔
1658
                f = handle_deserialize(s, tag)
445✔
1659
                na >= i && (vflds[i] = f)
445✔
1660
            else
1661
                na >= i && (na = i - 1) # rest of tail must be undefined values
×
1662
            end
1663
        end
461✔
1664
        return ccall(:jl_new_structv, Any, (Any, Ptr{Any}, UInt32), t, vflds, na)
429✔
1665
    end
1666
end
1667

1668
function deserialize_dict(s::AbstractSerializer, T::Type{<:AbstractDict})
661✔
1669
    n = read(s.io, Int32)
661✔
1670
    t = T(); sizehint!(t, n)
1,322✔
1671
    deserialize_cycle(s, t)
661✔
1672
    for i = 1:n
661✔
1673
        k = deserialize(s)
4,430✔
1674
        v = deserialize(s)
4,430✔
1675
        t[k] = v
4,430✔
1676
    end
8,199✔
1677
    return t
661✔
1678
end
1679

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

1684
deserialize(s::AbstractSerializer, ::Type{BigInt}) = parse(BigInt, deserialize(s), base = 62)
×
1685

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

1693
## StackTraces
1694

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

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

1719
function serialize(s::AbstractSerializer, lock::Base.AbstractLock)
×
1720
    # assert_havelock(lock)
1721
    serialize_cycle_header(s, lock)
×
1722
    nothing
×
1723
end
1724

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

1731
function serialize(s::AbstractSerializer, cond::Base.GenericCondition)
×
1732
    serialize_cycle_header(s, cond) && return
×
1733
    serialize(s, cond.lock)
×
1734
    nothing
×
1735
end
1736

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

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

1747
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