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

JuliaLang / julia / #37445

pending completion
#37445

push

local

web-flow
Relax abstractq test (#48694)

71667 of 82402 relevant lines covered (86.97%)

34379549.71 hits per line

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

92.52
/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)
242✔
27
end
28

29
Serializer(io::IO) = Serializer{typeof(io)}(io)
242✔
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, TypedSlot, 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
@assert length(TAGS) == 255
81

82
const ser_version = 23 # do not make changes without bumping the version #!
83

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

87
const NTAGS = length(TAGS)
88

89
function sertag(@nospecialize(v))
412,540✔
90
    # NOTE: we use jl_value_ptr directly since we know at least one of the arguments
91
    # in the comparison below is a singleton.
92
    ptr = ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), v)
413,629✔
93
    ptags = convert(Ptr{Ptr{Cvoid}}, pointer(TAGS))
413,629✔
94
    # note: constant ints & reserved slots never returned here
95
    @inbounds for i in 1:(NTAGS-(n_reserved_slots+2*n_int_literals))
413,629✔
96
        ptr == unsafe_load(ptags,i) && return i%Int32
53,255,442✔
97
    end
105,915,181✔
98
    return Int32(-1)
231,555✔
99
end
100
desertag(i::Int32) = @inbounds(TAGS[i])
353,094✔
101

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

146
writetag(s::IO, tag) = (write(s, UInt8(tag)); nothing)
1,817,666✔
147

148
function write_as_tag(s::IO, tag)
191,723✔
149
    tag < VALUE_TAGS && write(s, UInt8(0))
192,068✔
150
    write(s, UInt8(tag))
215,291✔
151
    nothing
191,918✔
152
end
153

154
# cycle handling
155
function serialize_cycle(s::AbstractSerializer, @nospecialize(x))
346,383✔
156
    offs = get(s.table, x, -1)::Int
375,394✔
157
    if offs != -1
346,383✔
158
        if offs <= typemax(UInt16)
29,011✔
159
            writetag(s.io, SHORTBACKREF_TAG)
29,089✔
160
            write(s.io, UInt16(offs))
29,010✔
161
        elseif offs <= typemax(Int32)
1✔
162
            writetag(s.io, BACKREF_TAG)
1✔
163
            write(s.io, Int32(offs))
1✔
164
        else
165
            writetag(s.io, LONGBACKREF_TAG)
×
166
            write(s.io, Int64(offs))
×
167
        end
168
        return true
29,011✔
169
    end
170
    s.table[x] = s.counter
317,372✔
171
    s.counter += 1
317,372✔
172
    return false
317,372✔
173
end
174

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

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

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

191
serialize(s::AbstractSerializer, p::Ptr) = serialize_any(s, oftype(p, C_NULL))
15✔
192

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

195
function serialize(s::AbstractSerializer, t::Tuple)
10,544✔
196
    l = length(t)
10,544✔
197
    if l <= 255
10,544✔
198
        writetag(s.io, TUPLE_TAG)
10,570✔
199
        write(s.io, UInt8(l))
10,570✔
200
    else
201
        writetag(s.io, LONGTUPLE_TAG)
2✔
202
        write(s.io, Int32(l))
1✔
203
    end
204
    for x in t
10,544✔
205
        serialize(s, x)
21,601✔
206
    end
17,468✔
207
end
208

209
function serialize(s::AbstractSerializer, v::SimpleVector)
1,203✔
210
    writetag(s.io, SIMPLEVECTOR_TAG)
1,227✔
211
    write(s.io, Int32(length(v)))
1,203✔
212
    for x in v
1,387✔
213
        serialize(s, x)
295✔
214
    end
295✔
215
end
216

217
function serialize(s::AbstractSerializer, x::Symbol)
132,050✔
218
    tag = sertag(x)
21,067,764✔
219
    if tag > 0
132,050✔
220
        return write_as_tag(s.io, tag)
45,630✔
221
    end
222
    pname = unsafe_convert(Ptr{UInt8}, x)
86,420✔
223
    len = Int(ccall(:strlen, Csize_t, (Cstring,), pname))
86,420✔
224
    if len > 7
86,420✔
225
        serialize_cycle(s, x) && return
46,322✔
226
    end
227
    if len <= 255
81,224✔
228
        writetag(s.io, SYMBOL_TAG)
81,492✔
229
        write(s.io, UInt8(len))
81,492✔
230
    else
231
        writetag(s.io, LONGSYMBOL_TAG)
2✔
232
        write(s.io, Int32(len))
1✔
233
    end
234
    unsafe_write(s.io, pname, len)
81,224✔
235
    nothing
81,224✔
236
end
237

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

259
function serialize(s::AbstractSerializer, a::Array)
9,035✔
260
    serialize_cycle(s, a) && return
9,035✔
261
    elty = eltype(a)
9,032✔
262
    writetag(s.io, ARRAY_TAG)
9,142✔
263
    if elty !== UInt8
9,033✔
264
        serialize(s, elty)
8,204✔
265
    end
266
    if ndims(a) != 1
9,032✔
267
        serialize(s, size(a))
64✔
268
    else
269
        serialize(s, length(a))
8,969✔
270
    end
271
    if isbitstype(elty)
9,032✔
272
        serialize_array_data(s.io, a)
3,002✔
273
    else
274
        sizehint!(s.table, div(length(a),4))  # prepare for lots of pointers
6,054✔
275
        @inbounds for i in eachindex(a)
8,545✔
276
            if isassigned(a, i)
253,032✔
277
                serialize(s, a[i])
276,096✔
278
            else
279
                writetag(s.io, UNDEFREF_TAG)
2✔
280
            end
281
        end
253,032✔
282
    end
283
end
284

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

292
function serialize(s::AbstractSerializer, ss::String)
204,922✔
293
    len = sizeof(ss)
204,922✔
294
    if len > 7
204,922✔
295
        serialize_cycle(s, ss) && return
203,243✔
296
        writetag(s.io, SHARED_REF_TAG)
201,965✔
297
    end
298
    if len <= 255
203,632✔
299
        writetag(s.io, STRING_TAG)
203,615✔
300
        write(s.io, UInt8(len))
203,615✔
301
    else
302
        writetag(s.io, LONGSTRING_TAG)
41✔
303
        write(s.io, Int64(len))
40✔
304
    end
305
    write(s.io, ss)
203,632✔
306
    nothing
203,632✔
307
end
308

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

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

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

327
function serialize(s::AbstractSerializer, ex::Expr)
4,048✔
328
    serialize_cycle(s, ex) && return
4,048✔
329
    l = length(ex.args)
4,048✔
330
    if l <= 255
4,048✔
331
        writetag(s.io, EXPR_TAG)
4,367✔
332
        write(s.io, UInt8(l))
4,367✔
333
    else
334
        writetag(s.io, LONGEXPR_TAG)
2✔
335
        write(s.io, Int32(l))
1✔
336
    end
337
    serialize(s, ex.head)
4,048✔
338
    for a in ex.args
4,052✔
339
        serialize(s, a)
9,646✔
340
    end
9,646✔
341
end
342

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

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

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

363
function serialize_mod_names(s::AbstractSerializer, m::Module)
59,003✔
364
    p = parentmodule(m)
59,003✔
365
    if p === m || m === Base
77,918✔
366
        key = Base.root_module_key(m)
58,728✔
367
        uuid = key.uuid
58,728✔
368
        serialize(s, uuid === nothing ? nothing : uuid.value)
76,311✔
369
        serialize(s, Symbol(key.name))
58,728✔
370
    else
371
        serialize_mod_names(s, p)
275✔
372
        serialize(s, nameof(m))
275✔
373
    end
374
end
375

376
function serialize(s::AbstractSerializer, m::Module)
58,728✔
377
    writetag(s.io, MODULE_TAG)
58,889✔
378
    serialize_mod_names(s, m)
58,728✔
379
    writetag(s.io, EMPTYTUPLE_TAG)
58,728✔
380
end
381

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

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

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

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

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

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

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

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

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

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

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

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

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

555
function serialize_type_data(s, @nospecialize(t::DataType))
81,325✔
556
    whole = should_send_whole_type(s, t)
162,072✔
557
    iswrapper = (t === unwrap_unionall(t.name.wrapper))
81,325✔
558
    if whole && iswrapper
81,325✔
559
        writetag(s.io, WRAPPER_DATATYPE_TAG)
5,105✔
560
        serialize(s, t.name)
5,088✔
561
        return
5,088✔
562
    end
563
    serialize_cycle(s, t) && return
76,237✔
564
    if whole
55,741✔
565
        writetag(s.io, FULL_DATATYPE_TAG)
243✔
566
        serialize(s, t.name)
241✔
567
    else
568
        writetag(s.io, DATATYPE_TAG)
55,630✔
569
        serialize(s, nameof(t))
55,500✔
570
        serialize(s, parentmodule(t))
55,500✔
571
    end
572
    if !isempty(t.parameters)
55,741✔
573
        if iswrapper
38,622✔
574
            write(s.io, Int32(0))
3✔
575
        else
576
            write(s.io, Int32(length(t.parameters)))
38,619✔
577
            for p in t.parameters
77,238✔
578
                serialize(s, p)
107,937✔
579
            end
107,937✔
580
        end
581
    end
582
    nothing
55,741✔
583
end
584

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

598
function serialize_type(s::AbstractSerializer, @nospecialize(t::DataType), ref::Bool = false)
66,074✔
599
    tag = sertag(t)
9,923,541✔
600
    tag > 0 && return writetag(s.io, tag)
64,959✔
601
    writetag(s.io, ref ? REF_OBJECT_TAG : OBJECT_TAG)
58,528✔
602
    serialize_type_data(s, t)
58,425✔
603
end
604

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

615
function serialize(s::AbstractSerializer, n::Int64)
44,450✔
616
    if 0 <= n <= (n_int_literals-1)
44,450✔
617
        write(s.io, UInt8(ZERO64_TAG+n))
36,914✔
618
    elseif typemin(Int32) <= n <= typemax(Int32)
8,117✔
619
        writetag(s.io, SHORTINT64_TAG)
7,960✔
620
        write(s.io, Int32(n))
7,946✔
621
    else
622
        writetag(s.io, INT64_TAG)
172✔
623
        write(s.io, n)
171✔
624
    end
625
    nothing
44,450✔
626
end
627

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

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

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

655
serialize(s::AbstractSerializer, @nospecialize(x)) = serialize_any(s, x)
131,889✔
656

657
function serialize_any(s::AbstractSerializer, @nospecialize(x))
131,919✔
658
    tag = sertag(x)
15,905,138✔
659
    if tag > 0
131,919✔
660
        return write_as_tag(s.io, tag)
68,107✔
661
    end
662
    t = typeof(x)::DataType
63,812✔
663
    if isprimitivetype(t)
63,812✔
664
        serialize_type(s, t)
38✔
665
        write(s.io, x)
38✔
666
    else
667
        if ismutable(x)
63,774✔
668
            serialize_cycle(s, x) && return
1,584✔
669
            serialize_type(s, t, true)
1,477✔
670
        else
671
            serialize_type(s, t, false)
62,190✔
672
        end
673
        nf = nfields(x)
63,667✔
674
        for i in 1:nf
94,183✔
675
            if isdefined(x, i)
73,676✔
676
                serialize(s, getfield(x, i))
73,675✔
677
            else
678
                writetag(s.io, UNDEFREF_TAG)
1✔
679
            end
680
        end
73,676✔
681
    end
682
    nothing
63,705✔
683
end
684

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

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

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

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

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

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

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

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

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

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

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

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

790
## deserializing values ##
791

792
"""
793
    deserialize(stream)
794

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

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

806
Open a file and deserialize its contents.
807

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

813
function deserialize(s::AbstractSerializer)
812,347✔
814
    handle_deserialize(s, Int32(read(s.io, UInt8)::UInt8))
812,367✔
815
end
816

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

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

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

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

847
# deserialize_ is an internal function to dispatch on the tag
848
# describing the serialized representation. the number of
849
# representations is fixed, so deserialize_ does not get extended.
850
function handle_deserialize(s::AbstractSerializer, b::Int32)
1,127,985✔
851
    if b == 0
1,127,985✔
852
        return desertag(Int32(read(s.io, UInt8)::UInt8))
25,452✔
853
    end
854
    if b >= VALUE_TAGS
1,102,533✔
855
        return desertag(b)
317,194✔
856
    elseif b == TUPLE_TAG
785,339✔
857
        return deserialize_tuple(s, Int(read(s.io, UInt8)::UInt8))
10,498✔
858
    elseif b == SHORTBACKREF_TAG
774,841✔
859
        id = read(s.io, UInt16)::UInt16
29,041✔
860
        return gettable(s, Int(id))
29,041✔
861
    elseif b == BACKREF_TAG
745,800✔
862
        id = read(s.io, Int32)::Int32
1✔
863
        return gettable(s, Int(id))
1✔
864
    elseif b == ARRAY_TAG
745,799✔
865
        return deserialize_array(s)
9,082✔
866
    elseif b == DATATYPE_TAG
736,717✔
867
        return deserialize_datatype(s, false)
55,616✔
868
    elseif b == FULL_DATATYPE_TAG
681,101✔
869
        return deserialize_datatype(s, true)
262✔
870
    elseif b == WRAPPER_DATATYPE_TAG
680,839✔
871
        tname = deserialize(s)::Core.TypeName
5,091✔
872
        return unwrap_unionall(tname.wrapper)
5,087✔
873
    elseif b == OBJECT_TAG
675,748✔
874
        t = deserialize(s)
57,585✔
875
        if t === Missing
57,581✔
876
            return missing
×
877
        end
878
        return deserialize(s, t)
57,581✔
879
    elseif b == REF_OBJECT_TAG
618,163✔
880
        slot = s.counter; s.counter += 1
1,964✔
881
        push!(s.pending_refs, slot)
982✔
882
        t = deserialize(s)
982✔
883
        return deserialize(s, t)
981✔
884
    elseif b == SHARED_REF_TAG
617,181✔
885
        slot = s.counter; s.counter += 1
403,814✔
886
        obj = deserialize(s)
201,907✔
887
        s.table[slot] = obj
201,907✔
888
        return obj
201,907✔
889
    elseif b == SYMBOL_TAG
415,274✔
890
        return deserialize_symbol(s, Int(read(s.io, UInt8)::UInt8))
81,317✔
891
    elseif b == SHORTINT64_TAG
333,957✔
892
        return Int64(read(s.io, Int32)::Int32)
8,055✔
893
    elseif b == EXPR_TAG
325,902✔
894
        return deserialize_expr(s, Int(read(s.io, UInt8)::UInt8))
4,005✔
895
    elseif b == MODULE_TAG
321,897✔
896
        return deserialize_module(s)
58,852✔
897
    elseif b == STRING_TAG
263,045✔
898
        return deserialize_string(s, Int(read(s.io, UInt8)::UInt8))
203,534✔
899
    elseif b == LONGSTRING_TAG
59,511✔
900
        return deserialize_string(s, Int(read(s.io, Int64)::Int64))
40✔
901
    elseif b == SIMPLEVECTOR_TAG
59,471✔
902
        return deserialize_svec(s)
1,210✔
903
    elseif b == GLOBALREF_TAG
58,261✔
904
        return GlobalRef(deserialize(s)::Module, deserialize(s)::Symbol)
1,777✔
905
    elseif b == FULL_GLOBALREF_TAG
56,484✔
906
        ty = deserialize(s)
13✔
907
        tn = unwrap_unionall(ty).name
13✔
908
        return GlobalRef(tn.module, tn.name)
13✔
909
    elseif b == LONGTUPLE_TAG
56,471✔
910
        return deserialize_tuple(s, Int(read(s.io, Int32)::Int32))
1✔
911
    elseif b == LONGEXPR_TAG
56,470✔
912
        return deserialize_expr(s, Int(read(s.io, Int32)::Int32))
1✔
913
    elseif b == LONGBACKREF_TAG
56,469✔
914
        id = read(s.io, Int64)::Int64
×
915
        return gettable(s, Int(id))
×
916
    elseif b == LONGSYMBOL_TAG
56,469✔
917
        return deserialize_symbol(s, Int(read(s.io, Int32)::Int32))
1✔
918
    elseif b == HEADER_TAG
56,468✔
919
        readheader(s)
120✔
920
        return deserialize(s)
116✔
921
    elseif b == INT8_TAG
56,348✔
922
        return read(s.io, Int8)
20✔
923
    elseif b == INT8_TAG+1
56,328✔
924
        return read(s.io, UInt8)
2,685✔
925
    elseif b == INT8_TAG+2
53,643✔
926
        return read(s.io, Int16)
12✔
927
    elseif b == INT8_TAG+3
53,631✔
928
        return read(s.io, UInt16)
413✔
929
    elseif b == INT32_TAG
53,218✔
930
        return read(s.io, Int32)
944✔
931
    elseif b == INT8_TAG+5
52,274✔
932
        return read(s.io, UInt32)
16✔
933
    elseif b == INT64_TAG
52,258✔
934
        return read(s.io, Int64)
175✔
935
    elseif b == INT8_TAG+7
52,083✔
936
        return read(s.io, UInt64)
1,015✔
937
    elseif b == INT8_TAG+8
51,068✔
938
        return read(s.io, Int128)
11,074✔
939
    elseif b == INT8_TAG+9
39,994✔
940
        return read(s.io, UInt128)
17,886✔
941
    elseif b == INT8_TAG+10
22,108✔
942
        return read(s.io, Float16)
4✔
943
    elseif b == INT8_TAG+11
22,104✔
944
        return read(s.io, Float32)
×
945
    elseif b == INT8_TAG+12
22,104✔
946
        return read(s.io, Float64)
517✔
947
    elseif b == INT8_TAG+13
21,587✔
948
        return read(s.io, Char)
11,137✔
949
    elseif b == IDDICT_TAG
10,450✔
950
        slot = s.counter; s.counter += 1
4✔
951
        push!(s.pending_refs, slot)
2✔
952
        t = deserialize(s)
2✔
953
        return deserialize_dict(s, t)
2✔
954
    end
955
    t = desertag(b)::DataType
10,448✔
956
    if ismutabletype(t) && length(t.types) > 0  # manual specialization of fieldcount
10,448✔
957
        slot = s.counter; s.counter += 1
9,000✔
958
        push!(s.pending_refs, slot)
4,500✔
959
    end
960
    return deserialize(s, t)
10,448✔
961
end
962

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

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

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

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

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

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

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

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

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

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

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

1269
function deserialize_fillarray!(A::Array{T}, s::AbstractSerializer) where {T}
6,095✔
1270
    for i = eachindex(A)
8,632✔
1271
        tag = Int32(read(s.io, UInt8)::UInt8)
253,053✔
1272
        if tag != UNDEFREF_TAG
253,053✔
1273
            @inbounds A[i] = handle_deserialize(s, tag)
253,051✔
1274
        end
1275
    end
503,567✔
1276
    return A
6,093✔
1277
end
1278

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

1287
module __deserialized_types__ end
1288

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

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

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

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

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

1383
function deserialize_datatype(s::AbstractSerializer, full::Bool)
55,878✔
1384
    slot = s.counter; s.counter += 1
111,756✔
1385
    if full
55,878✔
1386
        tname = deserialize(s)::Core.TypeName
262✔
1387
        ty = tname.wrapper
262✔
1388
    else
1389
        name = deserialize(s)::Symbol
55,616✔
1390
        mod = deserialize(s)::Module
55,616✔
1391
        ty = getglobal(mod, name)
55,616✔
1392
    end
1393
    if isa(ty,DataType) && isempty(ty.parameters)
55,874✔
1394
        t = ty
17,227✔
1395
    else
1396
        np = Int(read(s.io, Int32)::Int32)
38,647✔
1397
        if np == 0
38,647✔
1398
            t = unwrap_unionall(ty)
3✔
1399
        elseif ty === Tuple
38,644✔
1400
            # note np==0 has its own tag
1401
            if np == 1
1,677✔
1402
                t = Tuple{deserialize(s)}
1,059✔
1403
            elseif np == 2
618✔
1404
                t = Tuple{deserialize(s), deserialize(s)}
482✔
1405
            elseif np == 3
136✔
1406
                t = Tuple{deserialize(s), deserialize(s), deserialize(s)}
85✔
1407
            elseif np == 4
51✔
1408
                t = Tuple{deserialize(s), deserialize(s), deserialize(s), deserialize(s)}
29✔
1409
            else
1410
                t = Tuple{Any[ deserialize(s) for i=1:np ]...}
1,699✔
1411
            end
1412
        else
1413
            t = ty
36,960✔
1414
            for i = 1:np
73,934✔
1415
                t = t{deserialize(s)}
105,572✔
1416
            end
105,572✔
1417
        end
1418
    end
1419
    s.table[slot] = t
55,874✔
1420
    return t
55,874✔
1421
end
1422

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

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

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

1482
# default DataType deserializer
1483
function deserialize(s::AbstractSerializer, t::DataType)
62,748✔
1484
    nf = length(t.types)
62,748✔
1485
    if isprimitivetype(t)
62,748✔
1486
        return read(s.io, t)
35✔
1487
    elseif ismutabletype(t)
62,713✔
1488
        x = ccall(:jl_new_struct_uninit, Any, (Any,), t)
1,214✔
1489
        deserialize_cycle(s, x)
1,214✔
1490
        for i in 1:nf
2,426✔
1491
            tag = Int32(read(s.io, UInt8)::UInt8)
4,164✔
1492
            if tag != UNDEFREF_TAG
4,164✔
1493
                ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), x, i-1, handle_deserialize(s, tag))
3,711✔
1494
            end
1495
        end
7,116✔
1496
        return x
1,214✔
1497
    elseif nf == 0
61,499✔
1498
        return ccall(:jl_new_struct_uninit, Any, (Any,), t)
33,196✔
1499
    else
1500
        na = nf
28,303✔
1501
        vflds = Vector{Any}(undef, nf)
28,303✔
1502
        for i in 1:nf
56,606✔
1503
            tag = Int32(read(s.io, UInt8)::UInt8)
58,454✔
1504
            if tag != UNDEFREF_TAG
58,454✔
1505
                f = handle_deserialize(s, tag)
58,453✔
1506
                na >= i && (vflds[i] = f)
58,451✔
1507
            else
1508
                na >= i && (na = i - 1) # rest of tail must be undefined values
1✔
1509
            end
1510
        end
88,603✔
1511
        return ccall(:jl_new_structv, Any, (Any, Ptr{Any}, UInt32), t, vflds, na)
28,301✔
1512
    end
1513
end
1514

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

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

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

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

1540
## StackTraces
1541

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

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

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

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

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

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

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

1594
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