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

JuliaLang / julia / #37544

pending completion
#37544

push

local

web-flow
follow up #49889, pass `sv::AbsIntState` to `concrete_eval_call` (#49904)

`sv` is not used by `NativeInterpreter`, but is used by external
`AbstractInterpreter` like JET.jl.

1 of 1 new or added line in 1 file covered. (100.0%)

72304 of 83685 relevant lines covered (86.4%)

36045308.81 hits per line

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

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

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

10
import Base: GMP, Bottom, unsafe_convert, uncompressed_ast
11
import Core: svec, SimpleVector
12
using Base: unaliascopy, unwrap_unionall, require_one_based_indexing, ntupleany
13
using Core.IR
14

15
export serialize, deserialize, AbstractSerializer, Serializer
16

17
abstract type AbstractSerializer end
18

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

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

85
format_version(::AbstractSerializer) = ser_version
4,370✔
86
format_version(s::Serializer) = s.version
97✔
87

88
function sertag(@nospecialize(v))
418,206✔
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)
419,836✔
92
    ptags = convert(Ptr{Ptr{Cvoid}}, pointer(TAGS))
419,836✔
93
    # note: constant ints & reserved slots never returned here
94
    @inbounds for i in 1:(NTAGS-(n_reserved_slots+2*n_int_literals))
419,836✔
95
        ptr == unsafe_load(ptags,i) && return i%Int32
54,104,542✔
96
    end
107,604,962✔
97
    return Int32(-1)
235,550✔
98
end
99
desertag(i::Int32) = @inbounds(TAGS[i])
357,098✔
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)
1,833,209✔
146

147
function write_as_tag(s::IO, tag)
193,980✔
148
    tag < VALUE_TAGS && write(s, UInt8(0))
194,290✔
149
    write(s, UInt8(tag))
217,505✔
150
    nothing
194,159✔
151
end
152

153
# cycle handling
154
function serialize_cycle(s::AbstractSerializer, @nospecialize(x))
349,337✔
155
    offs = get(s.table, x, -1)::Int
379,558✔
156
    if offs != -1
349,337✔
157
        if offs <= typemax(UInt16)
30,221✔
158
            writetag(s.io, SHORTBACKREF_TAG)
30,220✔
159
            write(s.io, UInt16(offs))
30,220✔
160
        elseif offs <= typemax(Int32)
1✔
161
            writetag(s.io, BACKREF_TAG)
1✔
162
            write(s.io, Int32(offs))
1✔
163
        else
164
            writetag(s.io, LONGBACKREF_TAG)
×
165
            write(s.io, Int64(offs))
×
166
        end
167
        return true
30,221✔
168
    end
169
    s.table[x] = s.counter
319,116✔
170
    s.counter += 1
319,116✔
171
    return false
319,116✔
172
end
173

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

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

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

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

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

194
function serialize(s::AbstractSerializer, t::Tuple)
10,743✔
195
    l = length(t)
10,743✔
196
    if l <= NTAGS
10,743✔
197
        writetag(s.io, TUPLE_TAG)
10,742✔
198
        write(s.io, UInt8(l))
10,768✔
199
    else
200
        writetag(s.io, LONGTUPLE_TAG)
1✔
201
        write(s.io, Int32(l))
1✔
202
    end
203
    for x in t
10,743✔
204
        serialize(s, x)
22,012✔
205
    end
17,812✔
206
end
207

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

216
function serialize(s::AbstractSerializer, x::Symbol)
134,189✔
217
    tag = sertag(x)
21,414,519✔
218
    if tag > 0
134,189✔
219
        return write_as_tag(s.io, tag)
46,231✔
220
    end
221
    pname = unsafe_convert(Ptr{UInt8}, x)
87,958✔
222
    len = Int(ccall(:strlen, Csize_t, (Cstring,), pname))
87,958✔
223
    if len > 7
87,958✔
224
        serialize_cycle(s, x) && return
47,317✔
225
    end
226
    if len <= NTAGS
82,338✔
227
        writetag(s.io, SYMBOL_TAG)
82,331✔
228
        write(s.io, UInt8(len))
82,591✔
229
    else
230
        writetag(s.io, LONGSYMBOL_TAG)
7✔
231
        write(s.io, Int32(len))
7✔
232
    end
233
    unsafe_write(s.io, pname, len)
82,338✔
234
    nothing
82,338✔
235
end
236

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

258
function serialize(s::AbstractSerializer, a::Array)
9,239✔
259
    serialize_cycle(s, a) && return
9,239✔
260
    elty = eltype(a)
9,236✔
261
    writetag(s.io, ARRAY_TAG)
9,237✔
262
    if elty !== UInt8
9,237✔
263
        serialize(s, elty)
8,409✔
264
    end
265
    if ndims(a) != 1
9,236✔
266
        serialize(s, size(a))
64✔
267
    else
268
        serialize(s, length(a))
9,173✔
269
    end
270
    if isbitstype(elty)
9,236✔
271
        serialize_array_data(s.io, a)
3,020✔
272
    else
273
        sizehint!(s.table, div(length(a),4))  # prepare for lots of pointers
6,241✔
274
        @inbounds for i in eachindex(a)
8,928✔
275
            if isassigned(a, i)
253,410✔
276
                serialize(s, a[i])
254,435✔
277
            else
278
                writetag(s.io, UNDEFREF_TAG)
2✔
279
            end
280
        end
253,410✔
281
    end
282
end
283

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

291
function serialize(s::AbstractSerializer, ss::String)
205,180✔
292
    len = sizeof(ss)
205,180✔
293
    if len > 7
205,180✔
294
        serialize_cycle(s, ss) && return
203,398✔
295
        writetag(s.io, SHARED_REF_TAG)
201,993✔
296
    end
297
    if len <= NTAGS
203,775✔
298
        writetag(s.io, STRING_TAG)
203,731✔
299
        write(s.io, UInt8(len))
203,753✔
300
    else
301
        writetag(s.io, LONGSTRING_TAG)
44✔
302
        write(s.io, Int64(len))
44✔
303
    end
304
    write(s.io, ss)
203,775✔
305
    nothing
203,775✔
306
end
307

308
function serialize(s::AbstractSerializer, ss::SubString{String})
1✔
309
    # avoid saving a copy of the parent string, keeping the type of ss
310
    serialize_any(s, SubString(String(ss)))
1✔
311
end
312

313
# Don't serialize the pointers
314
function serialize(s::AbstractSerializer, r::Regex)
1✔
315
    serialize_type(s, typeof(r))
1✔
316
    serialize(s, r.pattern)
1✔
317
    serialize(s, r.compile_options)
1✔
318
    serialize(s, r.match_options)
1✔
319
end
320

321
function serialize(s::AbstractSerializer, n::BigInt)
×
322
    serialize_type(s, BigInt)
×
323
    serialize(s, string(n, base = 62))
×
324
end
325

326
function serialize(s::AbstractSerializer, ex::Expr)
4,134✔
327
    serialize_cycle(s, ex) && return
4,134✔
328
    l = length(ex.args)
4,134✔
329
    if l <= NTAGS
4,134✔
330
        writetag(s.io, EXPR_TAG)
4,133✔
331
        write(s.io, UInt8(l))
4,453✔
332
    else
333
        writetag(s.io, LONGEXPR_TAG)
1✔
334
        write(s.io, Int32(l))
1✔
335
    end
336
    serialize(s, ex.head)
4,134✔
337
    for a in ex.args
4,138✔
338
        serialize(s, a)
9,774✔
339
    end
9,774✔
340
end
341

342
function serialize_dict_data(s::AbstractSerializer, d::AbstractDict)
5✔
343
    write(s.io, Int32(length(d)))
5✔
344
    for (k,v) in d
9✔
345
        serialize(s, k)
175✔
346
        serialize(s, v)
175✔
347
    end
175✔
348
end
349

350
function serialize(s::AbstractSerializer, d::Dict)
3✔
351
    serialize_cycle_header(s, d) && return
6✔
352
    serialize_dict_data(s, d)
3✔
353
end
354

355
function serialize(s::AbstractSerializer, d::IdDict)
2✔
356
    serialize_cycle(s, d) && return
2✔
357
    writetag(s.io, IDDICT_TAG)
2✔
358
    serialize_type_data(s, typeof(d))
2✔
359
    serialize_dict_data(s, d)
2✔
360
end
361

362
function serialize_mod_names(s::AbstractSerializer, m::Module)
59,759✔
363
    p = parentmodule(m)
59,759✔
364
    if p === m || m === Base
78,936✔
365
        key = Base.root_module_key(m)
59,516✔
366
        uuid = key.uuid
59,516✔
367
        serialize(s, uuid === nothing ? nothing : uuid.value)
77,366✔
368
        serialize(s, Symbol(key.name))
59,516✔
369
    else
370
        serialize_mod_names(s, p)
243✔
371
        serialize(s, nameof(m))
243✔
372
    end
373
end
374

375
function serialize(s::AbstractSerializer, m::Module)
59,516✔
376
    writetag(s.io, MODULE_TAG)
59,516✔
377
    serialize_mod_names(s, m)
59,516✔
378
    writetag(s.io, EMPTYTUPLE_TAG)
59,516✔
379
end
380

381
# TODO: make this bidirectional, so objects can be sent back via the same key
382
const object_numbers = WeakKeyDict()
383
const obj_number_salt = Ref{UInt64}(0)
384
function object_number(s::AbstractSerializer, @nospecialize(l))
16✔
385
    global obj_number_salt, object_numbers
16✔
386
    if haskey(object_numbers, l)
16✔
387
        return object_numbers[l]
2✔
388
    end
389
    ln = obj_number_salt[]
14✔
390
    object_numbers[l] = ln
14✔
391
    obj_number_salt[] += 1
14✔
392
    return ln::UInt64
14✔
393
end
394

395
lookup_object_number(s::AbstractSerializer, n::UInt64) = nothing
×
396

397
remember_object(s::AbstractSerializer, @nospecialize(o), n::UInt64) = nothing
×
398

399
function lookup_object_number(s::Serializer, n::UInt64)
18✔
400
    return get(s.known_object_data, n, nothing)
20✔
401
end
402

403
function remember_object(s::Serializer, @nospecialize(o), n::UInt64)
17✔
404
    s.known_object_data[n] = o
17✔
405
    return nothing
17✔
406
end
407

408
function serialize(s::AbstractSerializer, meth::Method)
405✔
409
    serialize_cycle(s, meth) && return
405✔
410
    writetag(s.io, METHOD_TAG)
405✔
411
    write(s.io, object_number(s, meth))
660✔
412
    serialize(s, meth.module)
405✔
413
    serialize(s, meth.name)
405✔
414
    serialize(s, meth.file)
405✔
415
    serialize(s, meth.line)
405✔
416
    serialize(s, meth.sig)
405✔
417
    serialize(s, meth.slot_syms)
405✔
418
    serialize(s, meth.nargs)
405✔
419
    serialize(s, meth.isva)
810✔
420
    serialize(s, meth.is_for_opaque_closure)
810✔
421
    serialize(s, meth.constprop)
405✔
422
    serialize(s, meth.purity)
405✔
423
    if isdefined(meth, :source)
405✔
424
        serialize(s, Base._uncompressed_ast(meth, meth.source))
421✔
425
    else
426
        serialize(s, nothing)
×
427
    end
428
    if isdefined(meth, :generator)
405✔
429
        serialize(s, meth.generator)
×
430
    else
431
        serialize(s, nothing)
405✔
432
    end
433
    if isdefined(meth, :recursion_relation)
405✔
434
        serialize(s, method.recursion_relation)
×
435
    else
436
        serialize(s, nothing)
405✔
437
    end
438
    if isdefined(meth, :external_mt)
405✔
439
        error("cannot serialize Method objects with external method tables")
×
440
    end
441
    nothing
405✔
442
end
443

444
function serialize(s::AbstractSerializer, linfo::Core.MethodInstance)
×
445
    serialize_cycle(s, linfo) && return
×
446
    writetag(s.io, METHODINSTANCE_TAG)
×
447
    if isdefined(linfo, :uninferred)
×
448
        serialize(s, linfo.uninferred)
×
449
    else
450
        writetag(s.io, UNDEFREF_TAG)
×
451
    end
452
    serialize(s, nothing)  # for backwards compat
×
453
    serialize(s, linfo.sparam_vals)
×
454
    serialize(s, Any)  # for backwards compat
×
455
    serialize(s, linfo.specTypes)
×
456
    serialize(s, linfo.def)
×
457
    nothing
×
458
end
459

460
function serialize(s::AbstractSerializer, t::Task)
3✔
461
    serialize_cycle(s, t) && return
3✔
462
    if istaskstarted(t) && !istaskdone(t)
3✔
463
        error("cannot serialize a running Task")
×
464
    end
465
    writetag(s.io, TASK_TAG)
3✔
466
    serialize(s, t.code)
3✔
467
    serialize(s, t.storage)
3✔
468
    serialize(s, t.state)
6✔
469
    if t._isexception && (stk = Base.current_exceptions(t); !isempty(stk))
5✔
470
        # the exception stack field is hidden inside the task, so if there
471
        # is any information there make a CapturedException from it instead.
472
        # TODO: Handle full exception chain, not just the first one.
473
        serialize(s, CapturedException(stk[1].exception, stk[1].backtrace))
2✔
474
    else
475
        serialize(s, t.result)
1✔
476
    end
477
    serialize(s, t._isexception)
3✔
478
end
479

480
function serialize(s::AbstractSerializer, g::GlobalRef)
1,779✔
481
    if (g.mod === __deserialized_types__ ) ||
3,557✔
482
        (g.mod === Main && isdefined(g.mod, g.name) && isconst(g.mod, g.name))
483

484
        v = getglobal(g.mod, g.name)
567✔
485
        unw = unwrap_unionall(v)
567✔
486
        if isa(unw,DataType) && v === unw.name.wrapper && should_send_whole_type(s, unw)
595✔
487
            # handle references to types in Main by sending the whole type.
488
            # needed to be able to send nested functions (#15451).
489
            writetag(s.io, FULL_GLOBALREF_TAG)
13✔
490
            serialize(s, v)
13✔
491
            return
13✔
492
        end
493
    end
494
    writetag(s.io, GLOBALREF_TAG)
1,766✔
495
    serialize(s, g.mod)
1,766✔
496
    serialize(s, g.name)
1,766✔
497
end
498

499
function serialize(s::AbstractSerializer, t::Core.TypeName)
19✔
500
    serialize_cycle(s, t) && return
19✔
501
    writetag(s.io, TYPENAME_TAG)
8✔
502
    write(s.io, object_number(s, t))
15✔
503
    serialize_typename(s, t)
8✔
504
end
505

506
function serialize_typename(s::AbstractSerializer, t::Core.TypeName)
405✔
507
    serialize(s, t.name)
405✔
508
    serialize(s, t.names)
405✔
509
    primary = unwrap_unionall(t.wrapper)
405✔
510
    serialize(s, primary.super)
405✔
511
    serialize(s, primary.parameters)
405✔
512
    serialize(s, primary.types)
405✔
513
    serialize(s, isdefined(primary, :instance))
470✔
514
    serialize(s, t.flags & 0x1 == 0x1) # .abstract
810✔
515
    serialize(s, t.flags & 0x2 == 0x2) # .mutable
810✔
516
    serialize(s, Int32(length(primary.types) - t.n_uninitialized))
405✔
517
    serialize(s, t.max_methods)
405✔
518
    if isdefined(t, :mt) && t.mt !== Symbol.name.mt
405✔
519
        serialize(s, t.mt.name)
404✔
520
        serialize(s, collect(Base.MethodList(t.mt)))
808✔
521
        serialize(s, t.mt.max_args)
404✔
522
        kws = collect(methods(Core.kwcall, (Any, t.wrapper, Vararg)))
405✔
523
        if isempty(kws)
404✔
524
            writetag(s.io, UNDEFREF_TAG)
403✔
525
        else
526
            serialize(s, kws)
405✔
527
        end
528
    else
529
        writetag(s.io, UNDEFREF_TAG)
1✔
530
    end
531
    nothing
405✔
532
end
533

534
# decide whether to send all data for a type (instead of just its name)
535
function should_send_whole_type(s, t::DataType)
82,318✔
536
    tn = t.name
82,780✔
537
    if isdefined(tn, :mt)
82,780✔
538
        # TODO improve somehow
539
        # send whole type for anonymous functions in Main
540
        name = tn.mt.name
82,375✔
541
        mod = tn.module
82,375✔
542
        isanonfunction = mod === Main && # only Main
82,779✔
543
            t.super === Function && # only Functions
544
            unsafe_load(unsafe_convert(Ptr{UInt8}, tn.name)) == UInt8('#') && # hidden type
545
            (!isdefined(mod, name) || t != typeof(getglobal(mod, name))) # XXX: 95% accurate test for this being an inner function
546
            # TODO: more accurate test? (tn.name !== "#" name)
547
        #TODO: iskw = startswith(tn.name, "#kw#") && ???
548
        #TODO: iskw && return send-as-kwftype
549
        return mod === __deserialized_types__ || isanonfunction
164,595✔
550
    end
551
    return false
405✔
552
end
553

554
function serialize_type_data(s, @nospecialize(t::DataType))
82,751✔
555
    whole = should_send_whole_type(s, t)
164,943✔
556
    iswrapper = (t === unwrap_unionall(t.name.wrapper))
82,751✔
557
    if whole && iswrapper
82,751✔
558
        writetag(s.io, WRAPPER_DATATYPE_TAG)
5,063✔
559
        serialize(s, t.name)
5,063✔
560
        return
5,063✔
561
    end
562
    serialize_cycle(s, t) && return
77,688✔
563
    if whole
56,517✔
564
        writetag(s.io, FULL_DATATYPE_TAG)
246✔
565
        serialize(s, t.name)
246✔
566
    else
567
        writetag(s.io, DATATYPE_TAG)
56,271✔
568
        serialize(s, nameof(t))
56,271✔
569
        serialize(s, parentmodule(t))
56,271✔
570
    end
571
    if !isempty(t.parameters)
56,517✔
572
        if iswrapper
39,214✔
573
            write(s.io, Int32(0))
4✔
574
        else
575
            write(s.io, Int32(length(t.parameters)))
39,210✔
576
            for p in t.parameters
78,420✔
577
                serialize(s, p)
109,301✔
578
            end
109,301✔
579
        end
580
    end
581
    nothing
56,517✔
582
end
583

584
function serialize(s::AbstractSerializer, t::DataType)
85,898✔
585
    tag = sertag(t)
6,709,029✔
586
    tag > 0 && return write_as_tag(s.io, tag)
85,898✔
587
    if t === Tuple
23,377✔
588
        # `sertag` is not able to find types === to `Tuple` because they
589
        # will not have been hash-consed. Plus `serialize_type_data` does not
590
        # handle this case correctly, since Tuple{} != Tuple. `Tuple` is the
591
        # only type with this property. issue #15849
592
        return write_as_tag(s.io, TUPLE_TAG)
×
593
    end
594
    serialize_type_data(s, t)
23,377✔
595
end
596

597
function serialize_type(s::AbstractSerializer, @nospecialize(t::DataType), ref::Bool = false)
67,249✔
598
    tag = sertag(t)
10,085,010✔
599
    tag > 0 && return writetag(s.io, tag)
66,072✔
600
    writetag(s.io, ref ? REF_OBJECT_TAG : OBJECT_TAG)
59,372✔
601
    serialize_type_data(s, t)
59,372✔
602
end
603

604
function serialize(s::AbstractSerializer, n::Int32)
2,937✔
605
    if 0 <= n <= (n_int_literals-1)
2,937✔
606
        write(s.io, UInt8(ZERO32_TAG+n))
2,023✔
607
    else
608
        writetag(s.io, INT32_TAG)
944✔
609
        write(s.io, n)
944✔
610
    end
611
    nothing
2,937✔
612
end
613

614
function serialize(s::AbstractSerializer, n::Int64)
45,554✔
615
    if 0 <= n <= (n_int_literals-1)
45,554✔
616
        write(s.io, UInt8(ZERO64_TAG+n))
37,369✔
617
    elseif typemin(Int32) <= n <= typemax(Int32)
8,748✔
618
        writetag(s.io, SHORTINT64_TAG)
8,615✔
619
        write(s.io, Int32(n))
8,615✔
620
    else
621
        writetag(s.io, INT64_TAG)
133✔
622
        write(s.io, n)
133✔
623
    end
624
    nothing
45,554✔
625
end
626

627
for i in 0:13
628
    tag = Int32(INT8_TAG + i)
629
    ty = TAGS[tag]
630
    (ty === Int32 || ty === Int64) && continue
631
    @eval serialize(s::AbstractSerializer, n::$ty) = (writetag(s.io, $tag); write(s.io, n); nothing)
135,687✔
632
end
633

634
serialize(s::AbstractSerializer, ::Type{Bottom}) = write_as_tag(s.io, BOTTOM_TAG)
16,580✔
635

636
function serialize(s::AbstractSerializer, u::UnionAll)
71✔
637
    writetag(s.io, UNIONALL_TAG)
71✔
638
    n = 0; t = u
142✔
639
    while isa(t, UnionAll)
182✔
640
        t = t.body
111✔
641
        n += 1
111✔
642
    end
111✔
643
    if isa(t, DataType) && t === unwrap_unionall(t.name.wrapper)
71✔
644
        write(s.io, UInt8(1))
78✔
645
        write(s.io, Int16(n))
69✔
646
        serialize(s, t)
69✔
647
    else
648
        write(s.io, UInt8(0))
4✔
649
        serialize(s, u.var)
2✔
650
        serialize(s, u.body)
2✔
651
    end
652
end
653

654
serialize(s::AbstractSerializer, @nospecialize(x)) = serialize_any(s, x)
133,645✔
655

656
function serialize_any(s::AbstractSerializer, @nospecialize(x))
133,668✔
657
    tag = sertag(x)
16,132,288✔
658
    if tag > 0
133,668✔
659
        return write_as_tag(s.io, tag)
68,825✔
660
    end
661
    t = typeof(x)::DataType
64,843✔
662
    if isprimitivetype(t)
64,843✔
663
        serialize_type(s, t)
17✔
664
        write(s.io, x)
17✔
665
    else
666
        if ismutable(x)
64,826✔
667
            serialize_cycle(s, x) && return
1,663✔
668
            serialize_type(s, t, true)
1,555✔
669
        else
670
            serialize_type(s, t, false)
63,163✔
671
        end
672
        nf = nfields(x)
64,718✔
673
        for i in 1:nf
95,914✔
674
            if isdefined(x, i)
75,621✔
675
                serialize(s, getfield(x, i))
75,620✔
676
            else
677
                writetag(s.io, UNDEFREF_TAG)
1✔
678
            end
679
        end
75,619✔
680
    end
681
    nothing
64,733✔
682
end
683

684
"""
685
    Serialization.writeheader(s::AbstractSerializer)
686

687
Write an identifying header to the specified serializer. The header consists of
688
8 bytes as follows:
689

690
| Offset | Description                                     |
691
|:-------|:------------------------------------------------|
692
|   0    | tag byte (0x37)                                 |
693
|   1-2  | signature bytes "JL"                            |
694
|   3    | protocol version                                |
695
|   4    | bits 0-1: endianness: 0 = little, 1 = big       |
696
|   4    | bits 2-3: platform: 0 = 32-bit, 1 = 64-bit      |
697
|   5-7  | reserved                                        |
698
"""
699
function writeheader(s::AbstractSerializer)
113✔
700
    io = s.io
113✔
701
    writetag(io, HEADER_TAG)
113✔
702
    write(io, "JL")  # magic bytes
113✔
703
    write(io, UInt8(ser_version))
207✔
704
    endianness = (ENDIAN_BOM == 0x04030201 ? 0 :
94✔
705
                  ENDIAN_BOM == 0x01020304 ? 1 :
706
                  error("unsupported endianness in serializer"))
707
    machine = (sizeof(Int) == 4 ? 0 :
94✔
708
               sizeof(Int) == 8 ? 1 :
709
               error("unsupported word size in serializer"))
710
    write(io, UInt8(endianness) | (UInt8(machine) << 2))
207✔
711
    write(io, [0x00,0x00,0x00]) # 3 reserved bytes
339✔
712
    nothing
113✔
713
end
714

715
function readheader(s::AbstractSerializer)
109✔
716
    # Tag already read
717
    io = s.io
109✔
718
    m1 = read(io, UInt8)
109✔
719
    m2 = read(io, UInt8)
109✔
720
    if m1 != UInt8('J') || m2 != UInt8('L')
218✔
721
        error("Unsupported serialization format (got header magic bytes $m1 $m2)")
×
722
    end
723
    version    = read(io, UInt8)
109✔
724
    flags      = read(io, UInt8)
109✔
725
    reserved1  = read(io, UInt8)
109✔
726
    reserved2  = read(io, UInt8)
109✔
727
    reserved3  = read(io, UInt8)
109✔
728
    endianflag = flags & 0x3
109✔
729
    wordflag   = (flags >> 2) & 0x3
109✔
730
    wordsize = wordflag == 0 ? 4 :
216✔
731
               wordflag == 1 ? 8 :
732
               error("Unknown word size flag in header")
733
    endian_bom = endianflag == 0 ? 0x04030201 :
110✔
734
                 endianflag == 1 ? 0x01020304 :
735
                 error("Unknown endianness flag in header")
736
    # Check protocol compatibility.
737
    endian_bom == ENDIAN_BOM  || error("Serialized byte order mismatch ($(repr(endian_bom)))")
108✔
738
    # We don't check wordsize == sizeof(Int) here, as Int is encoded concretely
739
    # as Int32 or Int64, which should be enough to correctly deserialize a range
740
    # of data structures between Julia versions.
741
    if version > ser_version
106✔
742
        error("""Cannot read stream serialized with a newer version of Julia.
1✔
743
                 Got data version $version > current version $ser_version""")
744
    end
745
    s.version = version
105✔
746
    return
105✔
747
end
748

749
"""
750
    serialize(stream::IO, value)
751

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

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

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

769
In some cases, the word size (32- or 64-bit) of the reading and writing machines must match.
770
In rarer cases the OS or architecture must also match, for example when using packages
771
that contain platform-dependent code.
772
"""
773
function serialize(s::IO, x)
113✔
774
    ss = Serializer(s)
113✔
775
    writeheader(ss)
113✔
776
    serialize(ss, x)
113✔
777
end
778

779
"""
780
    serialize(filename::AbstractString, value)
781

782
Open a file and serialize the given value to it.
783

784
!!! compat "Julia 1.1"
785
    This method is available as of Julia 1.1.
786
"""
787
serialize(filename::AbstractString, x) = open(io->serialize(io, x), filename, "w")
2✔
788

789
## deserializing values ##
790

791
"""
792
    deserialize(stream)
793

794
Read a value written by [`serialize`](@ref). `deserialize` assumes the binary data read from
795
`stream` is correct and has been serialized by a compatible implementation of [`serialize`](@ref).
796
`deserialize` is designed for simplicity and performance, and so does not validate
797
the data read. Malformed data can result in process termination. The caller must ensure
798
the integrity and correctness of data read from `stream`.
799
"""
800
deserialize(s::IO) = deserialize(Serializer(s))
107✔
801

802
"""
803
    deserialize(filename::AbstractString)
804

805
Open a file and deserialize its contents.
806

807
!!! compat "Julia 1.1"
808
    This method is available as of Julia 1.1.
809
"""
810
deserialize(filename::AbstractString) = open(deserialize, filename)
1✔
811

812
function deserialize(s::AbstractSerializer)
820,622✔
813
    handle_deserialize(s, Int32(read(s.io, UInt8)::UInt8))
820,634✔
814
end
815

816
function deserialize_cycle(s::AbstractSerializer, @nospecialize(x))
5,544✔
817
    slot = pop!(s.pending_refs)
5,544✔
818
    s.table[slot] = x
5,544✔
819
    nothing
5,544✔
820
end
821

822
# optimized version of:
823
#     slot = s.counter; s.counter += 1
824
#     push!(s.pending_refs, slot)
825
#     slot = pop!(s.pending_refs)
826
#     s.table[slot] = x
827
function resolve_ref_immediately(s::AbstractSerializer, @nospecialize(x))
45,486✔
828
    s.table[s.counter] = x
45,753✔
829
    s.counter += 1
45,753✔
830
    nothing
45,486✔
831
end
832

833
function gettable(s::AbstractSerializer, id::Int)
29,533✔
834
    get(s.table, id) do
30,236✔
835
        errmsg = """Inconsistent Serializer state when deserializing.
×
836
            Attempt to access internal table with key $id failed.
837

838
            This might occur if the Serializer contexts when serializing and deserializing are inconsistent.
839
            In particular, if multiple serialize calls use the same Serializer object then
840
            the corresponding deserialize calls should also use the same Serializer object.
841
        """
842
        error(errmsg)
×
843
    end
844
end
845

846
# deserialize_ is an internal function to dispatch on the tag
847
# describing the serialized representation. the number of
848
# representations is fixed, so deserialize_ does not get extended.
849
function handle_deserialize(s::AbstractSerializer, b::Int32)
1,138,393✔
850
    if b == 0
1,138,393✔
851
        return desertag(Int32(read(s.io, UInt8)::UInt8))
25,660✔
852
    end
853
    if b >= VALUE_TAGS
1,112,733✔
854
        return desertag(b)
320,841✔
855
    elseif b == TUPLE_TAG
791,892✔
856
        return deserialize_tuple(s, Int(read(s.io, UInt8)::UInt8))
10,690✔
857
    elseif b == SHORTBACKREF_TAG
781,202✔
858
        id = read(s.io, UInt16)::UInt16
30,235✔
859
        return gettable(s, Int(id))
30,235✔
860
    elseif b == BACKREF_TAG
750,967✔
861
        id = read(s.io, Int32)::Int32
1✔
862
        return gettable(s, Int(id))
1✔
863
    elseif b == ARRAY_TAG
750,966✔
864
        return deserialize_array(s)
9,273✔
865
    elseif b == DATATYPE_TAG
741,693✔
866
        return deserialize_datatype(s, false)
56,368✔
867
    elseif b == FULL_DATATYPE_TAG
685,325✔
868
        return deserialize_datatype(s, true)
264✔
869
    elseif b == WRAPPER_DATATYPE_TAG
685,061✔
870
        tname = deserialize(s)::Core.TypeName
5,066✔
871
        return unwrap_unionall(tname.wrapper)
5,062✔
872
    elseif b == OBJECT_TAG
679,995✔
873
        t = deserialize(s)
58,434✔
874
        if t === Missing
58,430✔
875
            return missing
×
876
        end
877
        return deserialize(s, t)
58,430✔
878
    elseif b == REF_OBJECT_TAG
621,561✔
879
        slot = s.counter; s.counter += 1
2,106✔
880
        push!(s.pending_refs, slot)
1,053✔
881
        t = deserialize(s)
1,053✔
882
        return deserialize(s, t)
1,052✔
883
    elseif b == SHARED_REF_TAG
620,508✔
884
        slot = s.counter; s.counter += 1
403,898✔
885
        obj = deserialize(s)
201,949✔
886
        s.table[slot] = obj
201,949✔
887
        return obj
201,949✔
888
    elseif b == SYMBOL_TAG
418,559✔
889
        return deserialize_symbol(s, Int(read(s.io, UInt8)::UInt8))
82,382✔
890
    elseif b == SHORTINT64_TAG
336,177✔
891
        return Int64(read(s.io, Int32)::Int32)
8,694✔
892
    elseif b == EXPR_TAG
327,483✔
893
        return deserialize_expr(s, Int(read(s.io, UInt8)::UInt8))
4,083✔
894
    elseif b == MODULE_TAG
323,400✔
895
        return deserialize_module(s)
59,621✔
896
    elseif b == STRING_TAG
263,779✔
897
        return deserialize_string(s, Int(read(s.io, UInt8)::UInt8))
203,676✔
898
    elseif b == LONGSTRING_TAG
60,103✔
899
        return deserialize_string(s, Int(read(s.io, Int64)::Int64))
44✔
900
    elseif b == SIMPLEVECTOR_TAG
60,059✔
901
        return deserialize_svec(s)
1,222✔
902
    elseif b == GLOBALREF_TAG
58,837✔
903
        return GlobalRef(deserialize(s)::Module, deserialize(s)::Symbol)
1,771✔
904
    elseif b == FULL_GLOBALREF_TAG
57,066✔
905
        ty = deserialize(s)
13✔
906
        tn = unwrap_unionall(ty).name
13✔
907
        return GlobalRef(tn.module, tn.name)
13✔
908
    elseif b == LONGTUPLE_TAG
57,053✔
909
        return deserialize_tuple(s, Int(read(s.io, Int32)::Int32))
1✔
910
    elseif b == LONGEXPR_TAG
57,052✔
911
        return deserialize_expr(s, Int(read(s.io, Int32)::Int32))
1✔
912
    elseif b == LONGBACKREF_TAG
57,051✔
913
        id = read(s.io, Int64)::Int64
×
914
        return gettable(s, Int(id))
×
915
    elseif b == LONGSYMBOL_TAG
57,051✔
916
        return deserialize_symbol(s, Int(read(s.io, Int32)::Int32))
7✔
917
    elseif b == HEADER_TAG
57,044✔
918
        readheader(s)
109✔
919
        return deserialize(s)
105✔
920
    elseif b == INT8_TAG
56,935✔
921
        return read(s.io, Int8)
20✔
922
    elseif b == INT8_TAG+1
56,915✔
923
        return read(s.io, UInt8)
2,709✔
924
    elseif b == INT8_TAG+2
54,206✔
925
        return read(s.io, Int16)
12✔
926
    elseif b == INT8_TAG+3
54,194✔
927
        return read(s.io, UInt16)
417✔
928
    elseif b == INT32_TAG
53,777✔
929
        return read(s.io, Int32)
946✔
930
    elseif b == INT8_TAG+5
52,831✔
931
        return read(s.io, UInt32)
16✔
932
    elseif b == INT64_TAG
52,815✔
933
        return read(s.io, Int64)
141✔
934
    elseif b == INT8_TAG+7
52,674✔
935
        return read(s.io, UInt64)
1,193✔
936
    elseif b == INT8_TAG+8
51,481✔
937
        return read(s.io, Int128)
11,074✔
938
    elseif b == INT8_TAG+9
40,407✔
939
        return read(s.io, UInt128)
18,150✔
940
    elseif b == INT8_TAG+10
22,257✔
941
        return read(s.io, Float16)
4✔
942
    elseif b == INT8_TAG+11
22,253✔
943
        return read(s.io, Float32)
×
944
    elseif b == INT8_TAG+12
22,253✔
945
        return read(s.io, Float64)
517✔
946
    elseif b == INT8_TAG+13
21,736✔
947
        return read(s.io, Char)
11,137✔
948
    elseif b == IDDICT_TAG
10,599✔
949
        slot = s.counter; s.counter += 1
4✔
950
        push!(s.pending_refs, slot)
2✔
951
        t = deserialize(s)
2✔
952
        return deserialize_dict(s, t)
2✔
953
    end
954
    t = desertag(b)::DataType
10,597✔
955
    if ismutabletype(t) && length(t.types) > 0  # manual specialization of fieldcount
10,597✔
956
        slot = s.counter; s.counter += 1
8,988✔
957
        push!(s.pending_refs, slot)
4,494✔
958
    end
959
    return deserialize(s, t)
10,597✔
960
end
961

962
function deserialize_symbol(s::AbstractSerializer, len::Int)
82,389✔
963
    str = Base._string_n(len)
82,389✔
964
    unsafe_read(s.io, pointer(str), len)
82,389✔
965
    sym = Symbol(str)
82,389✔
966
    if len > 7
82,389✔
967
        resolve_ref_immediately(s, sym)
41,669✔
968
    end
969
    return sym
82,389✔
970
end
971

972
deserialize_tuple(s::AbstractSerializer, len) = ntupleany(i->deserialize(s), len)
28,529✔
973

974
function deserialize_svec(s::AbstractSerializer)
1,222✔
975
    n = read(s.io, Int32)
1,222✔
976
    svec(Any[ deserialize(s) for i=1:n ]...)
1,222✔
977
end
978

979
function deserialize_module(s::AbstractSerializer)
59,621✔
980
    mkey = deserialize(s)
59,621✔
981
    if isa(mkey, Tuple)
59,621✔
982
        # old version, TODO: remove
983
        if mkey === ()
×
984
            return Main
×
985
        end
986
        m = Base.root_module(mkey[1])
×
987
        for i = 2:length(mkey)
×
988
            m = getglobal(m, mkey[i])::Module
×
989
        end
×
990
    else
991
        name = String(deserialize(s)::Symbol)
59,621✔
992
        pkg = (mkey === nothing) ? Base.PkgId(name) : Base.PkgId(Base.UUID(mkey), name)
77,546✔
993
        m = Base.root_module(pkg)
59,621✔
994
        mname = deserialize(s)
59,621✔
995
        while mname !== ()
59,858✔
996
            m = getglobal(m, mname)::Module
239✔
997
            mname = deserialize(s)
237✔
998
        end
237✔
999
    end
1000
    return m
59,619✔
1001
end
1002

1003
function deserialize(s::AbstractSerializer, ::Type{Method})
407✔
1004
    lnumber = read(s.io, UInt64)
407✔
1005
    meth = lookup_object_number(s, lnumber)
408✔
1006
    if meth !== nothing
407✔
1007
        meth = meth::Method
1✔
1008
        makenew = false
1✔
1009
    else
1010
        meth = ccall(:jl_new_method_uninit, Ref{Method}, (Any,), Main)
406✔
1011
        makenew = true
406✔
1012
    end
1013
    deserialize_cycle(s, meth)
407✔
1014
    mod = deserialize(s)::Module
407✔
1015
    name = deserialize(s)::Symbol
407✔
1016
    file = deserialize(s)::Symbol
407✔
1017
    line = deserialize(s)::Int32
407✔
1018
    sig = deserialize(s)::Type
407✔
1019
    syms = deserialize(s)
407✔
1020
    if syms isa SimpleVector
407✔
1021
        # < v1.2
1022
        _ambig = deserialize(s)
1✔
1023
    else
1024
        slot_syms = syms::String
406✔
1025
    end
1026
    nargs = deserialize(s)::Int32
407✔
1027
    isva = deserialize(s)::Bool
407✔
1028
    is_for_opaque_closure = false
407✔
1029
    constprop = purity = 0x00
407✔
1030
    template_or_is_opaque = deserialize(s)
407✔
1031
    if isa(template_or_is_opaque, Bool)
407✔
1032
        is_for_opaque_closure = template_or_is_opaque
406✔
1033
        if format_version(s) >= 14
406✔
1034
            constprop = deserialize(s)::UInt8
406✔
1035
        end
1036
        if format_version(s) >= 17
406✔
1037
            purity = deserialize(s)::UInt8
406✔
1038
        end
1039
        template = deserialize(s)
406✔
1040
    else
1041
        template = template_or_is_opaque
1✔
1042
    end
1043
    generator = deserialize(s)
406✔
1044
    recursion_relation = nothing
406✔
1045
    if format_version(s) >= 15
406✔
1046
        recursion_relation = deserialize(s)
405✔
1047
    end
1048
    if makenew
406✔
1049
        meth.module = mod
405✔
1050
        meth.name = name
405✔
1051
        meth.file = file
405✔
1052
        meth.line = line
405✔
1053
        meth.sig = sig
405✔
1054
        meth.nargs = nargs
405✔
1055
        meth.isva = isva
405✔
1056
        meth.is_for_opaque_closure = is_for_opaque_closure
405✔
1057
        meth.constprop = constprop
405✔
1058
        meth.purity = purity
405✔
1059
        if template !== nothing
405✔
1060
            # TODO: compress template
1061
            meth.source = template::CodeInfo
405✔
1062
            if !@isdefined(slot_syms)
405✔
1063
                slot_syms = ccall(:jl_compress_argnames, Ref{String}, (Any,), meth.source.slotnames)
1✔
1064
            end
1065
        end
1066
        meth.slot_syms = slot_syms
405✔
1067
        if generator !== nothing
405✔
1068
            meth.generator = generator
×
1069
        end
1070
        if recursion_relation !== nothing
405✔
1071
            meth.recursion_relation = recursion_relation
×
1072
        end
1073
        if !is_for_opaque_closure
405✔
1074
            mt = ccall(:jl_method_table_for, Any, (Any,), sig)
405✔
1075
            if mt !== nothing && nothing === ccall(:jl_methtable_lookup, Any, (Any, Any, UInt), mt, sig, typemax(UInt))
405✔
1076
                ccall(:jl_method_table_insert, Cvoid, (Any, Any, Ptr{Cvoid}), mt, meth, C_NULL)
1✔
1077
            end
1078
        end
1079
        remember_object(s, meth, lnumber)
405✔
1080
    end
1081
    return meth
406✔
1082
end
1083

1084
function deserialize(s::AbstractSerializer, ::Type{Core.MethodInstance})
×
1085
    linfo = ccall(:jl_new_method_instance_uninit, Ref{Core.MethodInstance}, (Ptr{Cvoid},), C_NULL)
×
1086
    deserialize_cycle(s, linfo)
×
1087
    tag = Int32(read(s.io, UInt8)::UInt8)
×
1088
    if tag != UNDEFREF_TAG
×
1089
        setfield!(linfo, :uninferred, handle_deserialize(s, tag)::CodeInfo, :monotonic)
×
1090
    end
1091
    tag = Int32(read(s.io, UInt8)::UInt8)
×
1092
    if tag != UNDEFREF_TAG
×
1093
        # for reading files prior to v1.2
1094
        handle_deserialize(s, tag)
×
1095
    end
1096
    linfo.sparam_vals = deserialize(s)::SimpleVector
×
1097
    _rettype = deserialize(s)  # for backwards compat
×
1098
    linfo.specTypes = deserialize(s)
×
1099
    linfo.def = deserialize(s)
×
1100
    return linfo
×
1101
end
1102

1103
function deserialize(s::AbstractSerializer, ::Type{Core.LineInfoNode})
855✔
1104
    mod = deserialize(s)
855✔
1105
    if mod isa Module
855✔
1106
        method = deserialize(s)
855✔
1107
    else
1108
        # files post v1.2 and pre v1.6 are broken
1109
        method = mod
×
1110
        mod = Main
×
1111
    end
1112
    return Core.LineInfoNode(mod, method, deserialize(s)::Symbol, Int32(deserialize(s)::Union{Int32, Int}), Int32(deserialize(s)::Union{Int32, Int}))
855✔
1113
end
1114

1115
function deserialize(s::AbstractSerializer, ::Type{PhiNode})
×
1116
    edges = deserialize(s)
×
1117
    if edges isa Vector{Any}
×
1118
        edges = Vector{Int32}(edges)
×
1119
    end
1120
    values = deserialize(s)::Vector{Any}
×
1121
    return PhiNode(edges, values)
×
1122
end
1123

1124
function deserialize(s::AbstractSerializer, ::Type{CodeInfo})
407✔
1125
    ci = ccall(:jl_new_code_info_uninit, Ref{CodeInfo}, ())
407✔
1126
    deserialize_cycle(s, ci)
407✔
1127
    code = deserialize(s)::Vector{Any}
407✔
1128
    ci.code = code
406✔
1129
    # allow older-style IR with return and gotoifnot Exprs
1130
    for i in 1:length(code)
812✔
1131
        stmt = code[i]
2,674✔
1132
        if isa(stmt, Expr)
2,674✔
1133
            ex = stmt::Expr
1,654✔
1134
            if ex.head === :return
1,654✔
1135
                code[i] = ReturnNode(isempty(ex.args) ? nothing : ex.args[1])
2✔
1136
            elseif ex.head === :gotoifnot
1,653✔
1137
                code[i] = GotoIfNot(ex.args[1], ex.args[2])
×
1138
            end
1139
        end
1140
    end
4,942✔
1141
    ci.codelocs = deserialize(s)::Vector{Int32}
406✔
1142
    _x = deserialize(s)
406✔
1143
    if _x isa Array || _x isa Int
812✔
1144
        pre_12 = false
405✔
1145
        ci.ssavaluetypes = _x
405✔
1146
    else
1147
        pre_12 = true
1✔
1148
        # < v1.2
1149
        ci.method_for_inference_limit_heuristics = _x
1✔
1150
        ci.ssavaluetypes = deserialize(s)
1✔
1151
        ci.linetable = deserialize(s)
1✔
1152
    end
1153
    ssaflags = deserialize(s)
406✔
1154
    if length(ssaflags) ≠ length(code)
406✔
1155
        # make sure the length of `ssaflags` matches that of `code`
1156
        # so that the latest inference doesn't throw on IRs serialized from old versions
1157
        ssaflags = UInt8[0x00 for _ in 1:length(code)]
3✔
1158
    end
1159
    ci.ssaflags = ssaflags
406✔
1160
    if pre_12
406✔
1161
        ci.slotflags = deserialize(s)
1✔
1162
    else
1163
        ci.method_for_inference_limit_heuristics = deserialize(s)
405✔
1164
        ci.linetable = deserialize(s)
405✔
1165
    end
1166
    ci.slotnames = deserialize(s)
406✔
1167
    if !pre_12
406✔
1168
        ci.slotflags = deserialize(s)
405✔
1169
        ci.slottypes = deserialize(s)
405✔
1170
        ci.rettype = deserialize(s)
405✔
1171
        ci.parent = deserialize(s)
405✔
1172
        world_or_edges = deserialize(s)
405✔
1173
        pre_13 = isa(world_or_edges, Integer)
405✔
1174
        if pre_13
405✔
1175
            ci.min_world = world_or_edges
×
1176
        else
1177
            ci.edges = world_or_edges
405✔
1178
            ci.min_world = reinterpret(UInt, deserialize(s))
405✔
1179
            ci.max_world = reinterpret(UInt, deserialize(s))
405✔
1180
        end
1181
    end
1182
    ci.inferred = deserialize(s)
406✔
1183
    if format_version(s) < 22
406✔
1184
        inlining_cost = deserialize(s)
1✔
1185
        if isa(inlining_cost, Bool)
1✔
1186
            Core.Compiler.set_inlineable!(ci, inlining_cost)
1✔
1187
        else
1188
            ci.inlining_cost = inlining_cost
×
1189
        end
1190
    end
1191
    ci.propagate_inbounds = deserialize(s)
406✔
1192
    if format_version(s) < 23
406✔
1193
        deserialize(s) # `pure` field has been removed
1✔
1194
    end
1195
    if format_version(s) >= 20
406✔
1196
        ci.has_fcall = deserialize(s)
405✔
1197
    end
1198
    if format_version(s) >= 21
406✔
1199
        ci.inlining = deserialize(s)::UInt8
405✔
1200
    end
1201
    if format_version(s) >= 14
406✔
1202
        ci.constprop = deserialize(s)::UInt8
405✔
1203
    end
1204
    if format_version(s) >= 17
406✔
1205
        ci.purity = deserialize(s)::UInt8
405✔
1206
    end
1207
    if format_version(s) >= 22
406✔
1208
        ci.inlining_cost = deserialize(s)::UInt16
405✔
1209
    end
1210
    return ci
406✔
1211
end
1212

1213
if Int === Int64
1214
const OtherInt = Int32
1215
else
1216
const OtherInt = Int64
1217
end
1218

1219
function deserialize_array(s::AbstractSerializer)
9,273✔
1220
    slot = s.counter; s.counter += 1
18,546✔
1221
    d1 = deserialize(s)
9,273✔
1222
    if isa(d1, Type)
9,273✔
1223
        elty = d1
8,449✔
1224
        d1 = deserialize(s)
8,449✔
1225
    else
1226
        elty = UInt8
816✔
1227
    end
1228
    if isa(d1, Int32) || isa(d1, Int64)
18,546✔
1229
        if elty !== Bool && isbitstype(elty)
9,437✔
1230
            a = Vector{elty}(undef, d1)
2,949✔
1231
            s.table[slot] = a
2,949✔
1232
            return read!(s.io, a)
2,949✔
1233
        end
1234
        dims = (Int(d1),)
12,520✔
1235
    elseif d1 isa Dims
64✔
1236
        dims = d1::Dims
64✔
1237
    else
1238
        dims = convert(Dims, d1::Tuple{Vararg{OtherInt}})::Dims
×
1239
    end
1240
    if isbitstype(elty)
6,564✔
1241
        n = prod(dims)::Int
104✔
1242
        if elty === Bool && n > 0
52✔
1243
            A = Array{Bool, length(dims)}(undef, dims)
1✔
1244
            i = 1
1✔
1245
            while i <= n
6✔
1246
                b = read(s.io, UInt8)::UInt8
5✔
1247
                v = (b >> 7) != 0
5✔
1248
                count = b & 0x7f
5✔
1249
                nxt = i + count
5✔
1250
                while i < nxt
14✔
1251
                    A[i] = v
9✔
1252
                    i += 1
9✔
1253
                end
9✔
1254
            end
6✔
1255
        else
1256
            A = read!(s.io, Array{elty}(undef, dims))
51✔
1257
        end
1258
        s.table[slot] = A
52✔
1259
        return A
52✔
1260
    end
1261
    A = Array{elty, length(dims)}(undef, dims)
6,272✔
1262
    s.table[slot] = A
6,272✔
1263
    sizehint!(s.table, s.counter + div(length(A)::Int,4))
6,315✔
1264
    deserialize_fillarray!(A, s)
6,272✔
1265
    return A
6,270✔
1266
end
1267

1268
function deserialize_fillarray!(A::Array{T}, s::AbstractSerializer) where {T}
6,272✔
1269
    for i = eachindex(A)
9,003✔
1270
        tag = Int32(read(s.io, UInt8)::UInt8)
253,425✔
1271
        if tag != UNDEFREF_TAG
253,425✔
1272
            @inbounds A[i] = handle_deserialize(s, tag)
253,423✔
1273
        end
1274
    end
504,117✔
1275
    return A
6,270✔
1276
end
1277

1278
function deserialize_expr(s::AbstractSerializer, len)
4,084✔
1279
    e = Expr(:temp)
4,084✔
1280
    resolve_ref_immediately(s, e)
4,084✔
1281
    e.head = deserialize(s)::Symbol
4,084✔
1282
    e.args = Any[ deserialize(s) for i = 1:len ]
9,622✔
1283
    e
4,084✔
1284
end
1285

1286
module __deserialized_types__ end
1287

1288
function deserialize(s::AbstractSerializer, ::Type{Core.TypeName})
9✔
1289
    number = read(s.io, UInt64)
9✔
1290
    return deserialize_typename(s, number)
9✔
1291
end
1292

1293
function deserialize_typename(s::AbstractSerializer, number)
407✔
1294
    name = deserialize(s)::Symbol
407✔
1295
    tn = lookup_object_number(s, number)
409✔
1296
    if tn !== nothing
407✔
1297
        makenew = false
2✔
1298
    else
1299
        # reuse the same name for the type, if possible, for nicer debugging
1300
        tn_name = isdefined(__deserialized_types__, name) ? gensym() : name
405✔
1301
        tn = ccall(:jl_new_typename_in, Any, (Any, Any, Cint, Cint),
405✔
1302
                   tn_name, __deserialized_types__, false, false)
1303
        makenew = true
405✔
1304
    end
1305
    tn = tn::Core.TypeName
407✔
1306
    remember_object(s, tn, number)
407✔
1307
    deserialize_cycle(s, tn)
407✔
1308

1309
    names = deserialize(s)::SimpleVector
407✔
1310
    super = deserialize(s)::Type
407✔
1311
    parameters = deserialize(s)::SimpleVector
407✔
1312
    types = deserialize(s)::SimpleVector
407✔
1313
    attrs = Core.svec()
407✔
1314
    has_instance = deserialize(s)::Bool
407✔
1315
    abstr = deserialize(s)::Bool
407✔
1316
    mutabl = deserialize(s)::Bool
407✔
1317
    ninitialized = deserialize(s)::Int32
407✔
1318
    maxm = format_version(s) >= 18 ? deserialize(s)::UInt8 : UInt8(0)
407✔
1319

1320
    if makenew
407✔
1321
        # TODO: there's an unhanded cycle in the dependency graph at this point:
1322
        # while deserializing super and/or types, we may have encountered
1323
        # tn.wrapper and throw UndefRefException before we get to this point
1324
        ndt = ccall(:jl_new_datatype, Any, (Any, Any, Any, Any, Any, Any, Any, Cint, Cint, Cint),
405✔
1325
                    tn, tn.module, super, parameters, names, types, attrs,
1326
                    abstr, mutabl, ninitialized)
1327
        @assert tn == ndt.name
405✔
1328
        ccall(:jl_set_const, Cvoid, (Any, Any, Any), tn.module, tn.name, tn.wrapper)
405✔
1329
        ty = tn.wrapper
405✔
1330
        tn.max_methods = maxm
405✔
1331
        if has_instance
405✔
1332
            ty = ty::DataType
339✔
1333
            if !Base.issingletontype(ty)
339✔
1334
                singleton = ccall(:jl_new_struct, Any, (Any, Any...), ty)
×
1335
                # use setfield! directly to avoid `fieldtype` lowering expecting to see a Singleton object already on ty
1336
                ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), ty, Base.fieldindex(DataType, :instance)-1, singleton)
×
1337
            end
1338
        end
1339
    end
1340

1341
    tag = Int32(read(s.io, UInt8)::UInt8)
407✔
1342
    if tag != UNDEFREF_TAG
407✔
1343
        mtname = handle_deserialize(s, tag)
406✔
1344
        defs = deserialize(s)
406✔
1345
        maxa = deserialize(s)::Int
405✔
1346
        if makenew
405✔
1347
            mt = ccall(:jl_new_method_table, Any, (Any, Any), name, tn.module)
403✔
1348
            if !isempty(parameters)
403✔
1349
                mt.offs = 0
60✔
1350
            end
1351
            mt.name = mtname
403✔
1352
            setfield!(mt, :max_args, maxa, :monotonic)
403✔
1353
            ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), tn, Base.fieldindex(Core.TypeName, :mt)-1, mt)
403✔
1354
            for def in defs
403✔
1355
                if isdefined(def, :sig)
403✔
1356
                    ccall(:jl_method_table_insert, Cvoid, (Any, Any, Ptr{Cvoid}), mt, def, C_NULL)
403✔
1357
                end
1358
            end
403✔
1359
        end
1360
        tag = Int32(read(s.io, UInt8)::UInt8)
405✔
1361
        if tag != UNDEFREF_TAG
405✔
1362
            kws = handle_deserialize(s, tag)
1✔
1363
            if makenew
1✔
1364
                if kws isa Vector{Method}
1✔
1365
                    for def in kws
1✔
1366
                        kwmt = typeof(Core.kwcall).name.mt
1✔
1367
                        ccall(:jl_method_table_insert, Cvoid, (Any, Any, Ptr{Cvoid}), mt, def, C_NULL)
1✔
1368
                    end
2✔
1369
                else
1370
                    # old object format -- try to forward from old to new
1371
                    @eval Core.kwcall(kwargs::NamedTuple, f::$ty, args...) = $kws(kwargs, f, args...)
405✔
1372
                end
1373
            end
1374
        end
1375
    elseif makenew
1✔
1376
        mt = Symbol.name.mt
1✔
1377
        ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), tn, Base.fieldindex(Core.TypeName, :mt)-1, mt)
1✔
1378
    end
1379
    return tn
406✔
1380
end
1381

1382
function deserialize_datatype(s::AbstractSerializer, full::Bool)
56,632✔
1383
    slot = s.counter; s.counter += 1
113,264✔
1384
    if full
56,632✔
1385
        tname = deserialize(s)::Core.TypeName
264✔
1386
        ty = tname.wrapper
264✔
1387
    else
1388
        name = deserialize(s)::Symbol
56,368✔
1389
        mod = deserialize(s)::Module
56,368✔
1390
        ty = getglobal(mod, name)
56,368✔
1391
    end
1392
    if isa(ty,DataType) && isempty(ty.parameters)
56,628✔
1393
        t = ty
17,394✔
1394
    else
1395
        np = Int(read(s.io, Int32)::Int32)
39,234✔
1396
        if np == 0
39,234✔
1397
            t = unwrap_unionall(ty)
4✔
1398
        elseif ty === Tuple
39,230✔
1399
            # note np==0 has its own tag
1400
            if np == 1
1,687✔
1401
                t = Tuple{deserialize(s)}
1,069✔
1402
            elseif np == 2
618✔
1403
                t = Tuple{deserialize(s), deserialize(s)}
482✔
1404
            elseif np == 3
136✔
1405
                t = Tuple{deserialize(s), deserialize(s), deserialize(s)}
85✔
1406
            elseif np == 4
51✔
1407
                t = Tuple{deserialize(s), deserialize(s), deserialize(s), deserialize(s)}
29✔
1408
            else
1409
                t = Tuple{Any[ deserialize(s) for i=1:np ]...}
1,709✔
1410
            end
1411
        else
1412
            t = ty
37,540✔
1413
            for i = 1:np
75,086✔
1414
                t = t{deserialize(s)}
106,899✔
1415
            end
106,899✔
1416
        end
1417
    end
1418
    s.table[slot] = t
56,628✔
1419
    return t
56,628✔
1420
end
1421

1422
function deserialize(s::AbstractSerializer, ::Type{UnionAll})
72✔
1423
    form = read(s.io, UInt8)
72✔
1424
    if form == 0
72✔
1425
        var = deserialize(s)
2✔
1426
        body = deserialize(s)
2✔
1427
        return UnionAll(var, body)
2✔
1428
    else
1429
        n = read(s.io, Int16)
70✔
1430
        t = deserialize(s)::DataType
70✔
1431
        w = t.name.wrapper
70✔
1432
        k = 0
70✔
1433
        while isa(w, UnionAll)
181✔
1434
            w = w.body
111✔
1435
            k += 1
111✔
1436
        end
111✔
1437
        w = t.name.wrapper
70✔
1438
        k -= n
70✔
1439
        while k > 0
70✔
1440
            w = w.body
×
1441
            k -= 1
×
1442
        end
×
1443
        return w
70✔
1444
    end
1445
end
1446

1447
function deserialize(s::AbstractSerializer, ::Type{Task})
3✔
1448
    t = Task(()->nothing)
3✔
1449
    deserialize_cycle(s, t)
3✔
1450
    t.code = deserialize(s)
3✔
1451
    t.storage = deserialize(s)
3✔
1452
    state = deserialize(s)
3✔
1453
    if state === :runnable
3✔
1454
        t._state = Base.task_state_runnable
×
1455
    elseif state === :done
3✔
1456
        t._state = Base.task_state_done
1✔
1457
    elseif state === :failed
2✔
1458
        t._state = Base.task_state_failed
2✔
1459
    else
1460
        @assert false
×
1461
    end
1462
    t.result = deserialize(s)
3✔
1463
    exc = deserialize(s)
3✔
1464
    if exc === nothing
3✔
1465
        t._isexception = false
×
1466
    elseif exc isa Bool
3✔
1467
        t._isexception = exc
3✔
1468
    else
1469
        t._isexception = true
×
1470
        t.result = exc
×
1471
    end
1472
    t
3✔
1473
end
1474

1475
function deserialize_string(s::AbstractSerializer, len::Int)
203,683✔
1476
    out = ccall(:jl_alloc_string, Ref{String}, (Csize_t,), len)
203,720✔
1477
    unsafe_read(s.io, pointer(out), len)
203,720✔
1478
    return out
203,720✔
1479
end
1480

1481
# default DataType deserializer
1482
function deserialize(s::AbstractSerializer, t::DataType)
63,736✔
1483
    nf = length(t.types)
63,736✔
1484
    if isprimitivetype(t)
63,736✔
1485
        return read(s.io, t)
15✔
1486
    elseif ismutabletype(t)
63,721✔
1487
        x = ccall(:jl_new_struct_uninit, Any, (Any,), t)
1,288✔
1488
        deserialize_cycle(s, x)
1,288✔
1489
        for i in 1:nf
2,574✔
1490
            tag = Int32(read(s.io, UInt8)::UInt8)
4,317✔
1491
            if tag != UNDEFREF_TAG
4,317✔
1492
                ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), x, i-1, handle_deserialize(s, tag))
3,864✔
1493
            end
1494
        end
7,348✔
1495
        return x
1,288✔
1496
    elseif nf == 0
62,433✔
1497
        return ccall(:jl_new_struct_uninit, Any, (Any,), t)
33,557✔
1498
    else
1499
        na = nf
28,876✔
1500
        vflds = Vector{Any}(undef, nf)
28,876✔
1501
        for i in 1:nf
57,752✔
1502
            tag = Int32(read(s.io, UInt8)::UInt8)
60,066✔
1503
            if tag != UNDEFREF_TAG
60,066✔
1504
                f = handle_deserialize(s, tag)
60,065✔
1505
                na >= i && (vflds[i] = f)
60,063✔
1506
            else
1507
                na >= i && (na = i - 1) # rest of tail must be undefined values
1✔
1508
            end
1509
        end
91,254✔
1510
        return ccall(:jl_new_structv, Any, (Any, Ptr{Any}, UInt32), t, vflds, na)
28,874✔
1511
    end
1512
end
1513

1514
function deserialize_dict(s::AbstractSerializer, T::Type{<:AbstractDict})
5✔
1515
    n = read(s.io, Int32)
5✔
1516
    t = T(); sizehint!(t, n)
11✔
1517
    deserialize_cycle(s, t)
5✔
1518
    for i = 1:n
9✔
1519
        k = deserialize(s)
175✔
1520
        v = deserialize(s)
175✔
1521
        t[k] = v
175✔
1522
    end
346✔
1523
    return t
5✔
1524
end
1525

1526
function deserialize(s::AbstractSerializer, T::Type{Dict{K,V}}) where {K,V}
3✔
1527
    return deserialize_dict(s, T)
3✔
1528
end
1529

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

1532
function deserialize(s::AbstractSerializer, t::Type{Regex})
1✔
1533
    pattern = deserialize(s)
1✔
1534
    compile_options = deserialize(s)
1✔
1535
    match_options = deserialize(s)
1✔
1536
    return Regex(pattern, compile_options, match_options)
1✔
1537
end
1538

1539
## StackTraces
1540

1541
# provide a custom serializer that skips attempting to serialize the `outer_linfo`
1542
# which is likely to contain complex references, types, and module references
1543
# that may not exist on the receiver end
1544
function serialize(s::AbstractSerializer, frame::Base.StackTraces.StackFrame)
1,063✔
1545
    serialize_type(s, typeof(frame))
1,063✔
1546
    serialize(s, frame.func)
1,063✔
1547
    serialize(s, frame.file)
1,063✔
1548
    write(s.io, frame.line)
1,063✔
1549
    write(s.io, frame.from_c)
1,063✔
1550
    write(s.io, frame.inlined)
1,063✔
1551
    write(s.io, frame.pointer)
1,063✔
1552
    nothing
1,063✔
1553
end
1554

1555
function deserialize(s::AbstractSerializer, ::Type{Base.StackTraces.StackFrame})
1,063✔
1556
    func = deserialize(s)
1,063✔
1557
    file = deserialize(s)
1,063✔
1558
    line = read(s.io, Int)
1,063✔
1559
    from_c = read(s.io, Bool)
1,063✔
1560
    inlined = read(s.io, Bool)
1,063✔
1561
    pointer = read(s.io, UInt64)
1,063✔
1562
    return Base.StackTraces.StackFrame(func, file, line, nothing, from_c, inlined, pointer)
1,063✔
1563
end
1564

1565
function serialize(s::AbstractSerializer, lock::Base.AbstractLock)
18✔
1566
    # assert_havelock(lock)
1567
    serialize_cycle_header(s, lock)
35✔
1568
    nothing
18✔
1569
end
1570

1571
function deserialize(s::AbstractSerializer, ::Type{T}) where T<:Base.AbstractLock
17✔
1572
    lock = T()
17✔
1573
    deserialize_cycle(s, lock)
17✔
1574
    return lock
17✔
1575
end
1576

1577
function serialize(s::AbstractSerializer, cond::Base.GenericCondition)
2✔
1578
    serialize_cycle_header(s, cond) && return
4✔
1579
    serialize(s, cond.lock)
3✔
1580
    nothing
2✔
1581
end
1582

1583
function deserialize(s::AbstractSerializer, ::Type{T}) where T<:Base.GenericCondition
2✔
1584
    lock = deserialize(s)
2✔
1585
    cond = T(lock)
2✔
1586
    deserialize_cycle(s, cond)
2✔
1587
    return cond
2✔
1588
end
1589

1590
serialize(s::AbstractSerializer, l::LazyString) =
2✔
1591
    invoke(serialize, Tuple{AbstractSerializer,Any}, s, Base._LazyString((), string(l)))
1592

1593
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