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

JuliaLang / julia / #37433

pending completion
#37433

push

local

web-flow
Merge pull request #48513 from JuliaLang/jn/extend-once

ensure extension triggers are only run by the package that satified them

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

72324 of 82360 relevant lines covered (87.81%)

31376331.4 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)
235✔
27
end
28

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

84
format_version(::AbstractSerializer) = ser_version
3,090✔
85
format_version(s::Serializer) = s.version
88✔
86

87
const NTAGS = length(TAGS)
88

89
function sertag(@nospecialize(v))
402,538✔
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)
404,216✔
93
    ptags = convert(Ptr{Ptr{Cvoid}}, pointer(TAGS))
404,216✔
94
    # note: constant ints & reserved slots never returned here
95
    @inbounds for i in 1:(NTAGS-(n_reserved_slots+2*n_int_literals))
404,216✔
96
        ptr == unsafe_load(ptags,i) && return i%Int32
52,072,614✔
97
    end
103,562,956✔
98
    return Int32(-1)
226,160✔
99
end
100
desertag(i::Int32) = @inbounds(TAGS[i])
346,705✔
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,795,955✔
147

148
function write_as_tag(s::IO, tag)
188,120✔
149
    tag < VALUE_TAGS && write(s, UInt8(0))
188,449✔
150
    write(s, UInt8(tag))
211,672✔
151
    nothing
188,299✔
152
end
153

154
# cycle handling
155
function serialize_cycle(s::AbstractSerializer, @nospecialize(x))
343,196✔
156
    offs = get(s.table, x, -1)::Int
370,834✔
157
    if offs != -1
343,196✔
158
        if offs <= typemax(UInt16)
27,638✔
159
            writetag(s.io, SHORTBACKREF_TAG)
27,716✔
160
            write(s.io, UInt16(offs))
27,637✔
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
27,638✔
169
    end
170
    s.table[x] = s.counter
315,558✔
171
    s.counter += 1
315,558✔
172
    return false
315,558✔
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)
60,958✔
182
    s.counter = 0
62,560✔
183
    empty!(s.table)
62,560✔
184
    empty!(s.pending_refs)
62,560✔
185
    s
62,560✔
186
end
187

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

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

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

195
function serialize(s::AbstractSerializer, t::Tuple)
10,135✔
196
    l = length(t)
10,135✔
197
    if l <= 255
10,135✔
198
        writetag(s.io, TUPLE_TAG)
10,161✔
199
        write(s.io, UInt8(l))
10,161✔
200
    else
201
        writetag(s.io, LONGTUPLE_TAG)
2✔
202
        write(s.io, Int32(l))
1✔
203
    end
204
    for x in t
10,135✔
205
        serialize(s, x)
20,811✔
206
    end
16,903✔
207
end
208

209
function serialize(s::AbstractSerializer, v::SimpleVector)
1,182✔
210
    writetag(s.io, SIMPLEVECTOR_TAG)
1,206✔
211
    write(s.io, Int32(length(v)))
1,182✔
212
    for x in v
1,347✔
213
        serialize(s, x)
261✔
214
    end
261✔
215
end
216

217
function serialize(s::AbstractSerializer, x::Symbol)
129,339✔
218
    tag = sertag(x)
20,631,648✔
219
    if tag > 0
129,339✔
220
        return write_as_tag(s.io, tag)
44,949✔
221
    end
222
    pname = unsafe_convert(Ptr{UInt8}, x)
84,390✔
223
    len = Int(ccall(:strlen, Csize_t, (Cstring,), pname))
84,390✔
224
    if len > 7
84,390✔
225
        serialize_cycle(s, x) && return
45,298✔
226
    end
227
    if len <= 255
79,535✔
228
        writetag(s.io, SYMBOL_TAG)
79,800✔
229
        write(s.io, UInt8(len))
79,800✔
230
    else
231
        writetag(s.io, LONGSYMBOL_TAG)
5✔
232
        write(s.io, Int32(len))
4✔
233
    end
234
    unsafe_write(s.io, pname, len)
79,535✔
235
    nothing
79,535✔
236
end
237

238
function serialize_array_data(s::IO, a)
2,879✔
239
    require_one_based_indexing(a)
2,879✔
240
    isempty(a) && return 0
2,879✔
241
    if eltype(a) === Bool
2,871✔
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,870✔
256
    end
257
end
258

259
function serialize(s::AbstractSerializer, a::Array)
9,007✔
260
    serialize_cycle(s, a) && return
9,007✔
261
    elty = eltype(a)
9,005✔
262
    writetag(s.io, ARRAY_TAG)
9,114✔
263
    if elty !== UInt8
9,005✔
264
        serialize(s, elty)
8,196✔
265
    end
266
    if ndims(a) != 1
9,005✔
267
        serialize(s, size(a))
64✔
268
    else
269
        serialize(s, length(a))
8,941✔
270
    end
271
    if isbitstype(elty)
9,005✔
272
        serialize_array_data(s.io, a)
2,879✔
273
    else
274
        sizehint!(s.table, div(length(a),4))  # prepare for lots of pointers
6,146✔
275
        @inbounds for i in eachindex(a)
8,737✔
276
            if isassigned(a, i)
252,579✔
277
                serialize(s, a[i])
275,113✔
278
            else
279
                writetag(s.io, UNDEFREF_TAG)
2✔
280
            end
281
        end
252,579✔
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)
203,714✔
293
    len = sizeof(ss)
203,714✔
294
    if len > 7
203,714✔
295
        serialize_cycle(s, ss) && return
202,592✔
296
        writetag(s.io, SHARED_REF_TAG)
201,888✔
297
    end
298
    if len <= 255
202,998✔
299
        writetag(s.io, STRING_TAG)
202,980✔
300
        write(s.io, UInt8(len))
202,980✔
301
    else
302
        writetag(s.io, LONGSTRING_TAG)
42✔
303
        write(s.io, Int64(len))
41✔
304
    end
305
    write(s.io, ss)
202,998✔
306
    nothing
202,998✔
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)
3,914✔
328
    serialize_cycle(s, ex) && return
3,914✔
329
    l = length(ex.args)
3,914✔
330
    if l <= 255
3,914✔
331
        writetag(s.io, EXPR_TAG)
4,233✔
332
        write(s.io, UInt8(l))
4,233✔
333
    else
334
        writetag(s.io, LONGEXPR_TAG)
2✔
335
        write(s.io, Int32(l))
1✔
336
    end
337
    serialize(s, ex.head)
3,914✔
338
    for a in ex.args
3,918✔
339
        serialize(s, a)
9,307✔
340
    end
9,307✔
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)
152✔
347
        serialize(s, v)
152✔
348
    end
152✔
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)
58,113✔
364
    p = parentmodule(m)
58,113✔
365
    if p === m || m === Base
76,753✔
366
        key = Base.root_module_key(m)
57,849✔
367
        uuid = key.uuid
57,849✔
368
        serialize(s, uuid === nothing ? nothing : uuid.value)
75,157✔
369
        serialize(s, Symbol(key.name))
57,849✔
370
    else
371
        serialize_mod_names(s, p)
264✔
372
        serialize(s, nameof(m))
264✔
373
    end
374
end
375

376
function serialize(s::AbstractSerializer, m::Module)
57,849✔
377
    writetag(s.io, MODULE_TAG)
58,010✔
378
    serialize_mod_names(s, m)
57,849✔
379
    writetag(s.io, EMPTYTUPLE_TAG)
57,849✔
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)
394✔
410
    serialize_cycle(s, meth) && return
394✔
411
    writetag(s.io, METHOD_TAG)
402✔
412
    write(s.io, object_number(s, meth))
639✔
413
    serialize(s, meth.module)
394✔
414
    serialize(s, meth.name)
394✔
415
    serialize(s, meth.file)
394✔
416
    serialize(s, meth.line)
394✔
417
    serialize(s, meth.sig)
394✔
418
    serialize(s, meth.slot_syms)
394✔
419
    serialize(s, meth.nargs)
394✔
420
    serialize(s, meth.isva)
780✔
421
    serialize(s, meth.is_for_opaque_closure)
780✔
422
    serialize(s, meth.constprop)
394✔
423
    serialize(s, meth.purity)
394✔
424
    if isdefined(meth, :source)
394✔
425
        serialize(s, Base._uncompressed_ast(meth, meth.source))
772✔
426
    else
427
        serialize(s, nothing)
×
428
    end
429
    if isdefined(meth, :generator)
394✔
430
        serialize(s, meth.generator)
×
431
    else
432
        serialize(s, nothing)
394✔
433
    end
434
    if isdefined(meth, :recursion_relation)
394✔
435
        serialize(s, method.recursion_relation)
×
436
    else
437
        serialize(s, nothing)
394✔
438
    end
439
    if isdefined(meth, :external_mt)
394✔
440
        error("cannot serialize Method objects with external method tables")
×
441
    end
442
    nothing
394✔
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,762✔
482
    if (g.mod === __deserialized_types__ ) ||
3,523✔
483
        (g.mod === Main && isdefined(g.mod, g.name) && isconst(g.mod, g.name))
484

485
        v = getglobal(g.mod, g.name)
569✔
486
        unw = unwrap_unionall(v)
569✔
487
        if isa(unw,DataType) && v === unw.name.wrapper && should_send_whole_type(s, unw)
597✔
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,763✔
496
    serialize(s, g.mod)
1,749✔
497
    serialize(s, g.name)
1,749✔
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)
394✔
508
    serialize(s, t.name)
394✔
509
    serialize(s, t.names)
394✔
510
    primary = unwrap_unionall(t.wrapper)
394✔
511
    serialize(s, primary.super)
394✔
512
    serialize(s, primary.parameters)
394✔
513
    serialize(s, primary.types)
394✔
514
    serialize(s, isdefined(primary, :instance))
447✔
515
    serialize(s, t.flags & 0x1 == 0x1) # .abstract
780✔
516
    serialize(s, t.flags & 0x2 == 0x2) # .mutable
780✔
517
    serialize(s, Int32(length(primary.types) - t.n_uninitialized))
394✔
518
    serialize(s, t.max_methods)
394✔
519
    if isdefined(t, :mt) && t.mt !== Symbol.name.mt
394✔
520
        serialize(s, t.mt.name)
393✔
521
        serialize(s, collect(Base.MethodList(t.mt)))
786✔
522
        serialize(s, t.mt.max_args)
393✔
523
        kws = collect(methods(Core.kwcall, (Any, t.wrapper, Vararg)))
394✔
524
        if isempty(kws)
393✔
525
            writetag(s.io, UNDEFREF_TAG)
398✔
526
        else
527
            serialize(s, kws)
394✔
528
        end
529
    else
530
        writetag(s.io, UNDEFREF_TAG)
1✔
531
    end
532
    nothing
394✔
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)
79,624✔
537
    tn = t.name
80,060✔
538
    if isdefined(tn, :mt)
80,060✔
539
        # TODO improve somehow
540
        # send whole type for anonymous functions in Main
541
        name = tn.mt.name
79,666✔
542
        mod = tn.module
79,666✔
543
        isanonfunction = mod === Main && # only Main
80,065✔
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
159,179✔
551
    end
552
    return false
394✔
553
end
554

555
function serialize_type_data(s, @nospecialize(t::DataType))
80,031✔
556
    whole = should_send_whole_type(s, t)
159,516✔
557
    iswrapper = (t === unwrap_unionall(t.name.wrapper))
80,031✔
558
    if whole && iswrapper
80,031✔
559
        writetag(s.io, WRAPPER_DATATYPE_TAG)
5,083✔
560
        serialize(s, t.name)
5,066✔
561
        return
5,066✔
562
    end
563
    serialize_cycle(s, t) && return
74,965✔
564
    if whole
54,910✔
565
        writetag(s.io, FULL_DATATYPE_TAG)
246✔
566
        serialize(s, t.name)
244✔
567
    else
568
        writetag(s.io, DATATYPE_TAG)
54,796✔
569
        serialize(s, nameof(t))
54,666✔
570
        serialize(s, parentmodule(t))
54,666✔
571
    end
572
    if !isempty(t.parameters)
54,910✔
573
        if iswrapper
38,083✔
574
            write(s.io, Int32(0))
3✔
575
        else
576
            write(s.io, Int32(length(t.parameters)))
38,080✔
577
            for p in t.parameters
76,160✔
578
                serialize(s, p)
106,361✔
579
            end
106,361✔
580
        end
581
    end
582
    nothing
54,910✔
583
end
584

585
function serialize(s::AbstractSerializer, t::DataType)
83,598✔
586
    tag = sertag(t)
6,524,398✔
587
    tag > 0 && return write_as_tag(s.io, tag)
83,598✔
588
    if t === Tuple
22,754✔
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,754✔
596
end
597

598
function serialize_type(s::AbstractSerializer, @nospecialize(t::DataType), ref::Bool = false)
64,486✔
599
    tag = sertag(t)
9,716,303✔
600
    tag > 0 && return writetag(s.io, tag)
63,140✔
601
    writetag(s.io, ref ? REF_OBJECT_TAG : OBJECT_TAG)
57,378✔
602
    serialize_type_data(s, t)
57,275✔
603
end
604

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

615
function serialize(s::AbstractSerializer, n::Int64)
43,440✔
616
    if 0 <= n <= (n_int_literals-1)
43,440✔
617
        write(s.io, UInt8(ZERO64_TAG+n))
36,679✔
618
    elseif typemin(Int32) <= n <= typemax(Int32)
7,342✔
619
        writetag(s.io, SHORTINT64_TAG)
7,195✔
620
        write(s.io, Int32(n))
7,181✔
621
    else
622
        writetag(s.io, INT64_TAG)
162✔
623
        write(s.io, n)
161✔
624
    end
625
    nothing
43,440✔
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,278✔
633
end
634

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

637
function serialize(s::AbstractSerializer, u::UnionAll)
63✔
638
    writetag(s.io, UNIONALL_TAG)
73✔
639
    n = 0; t = u
126✔
640
    while isa(t, UnionAll)
158✔
641
        t = t.body
95✔
642
        n += 1
95✔
643
    end
95✔
644
    if isa(t, DataType) && t === unwrap_unionall(t.name.wrapper)
63✔
645
        write(s.io, UInt8(1))
69✔
646
        write(s.io, Int16(n))
61✔
647
        serialize(s, t)
61✔
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)
128,104✔
656

657
function serialize_any(s::AbstractSerializer, @nospecialize(x))
128,130✔
658
    tag = sertag(x)
15,427,348✔
659
    if tag > 0
128,130✔
660
        return write_as_tag(s.io, tag)
66,389✔
661
    end
662
    t = typeof(x)::DataType
61,741✔
663
    if isprimitivetype(t)
61,741✔
664
        serialize_type(s, t)
28✔
665
        write(s.io, x)
28✔
666
    else
667
        if ismutable(x)
61,713✔
668
            serialize_cycle(s, x) && return
1,532✔
669
            serialize_type(s, t, true)
1,436✔
670
        else
671
            serialize_type(s, t, false)
60,181✔
672
        end
673
        nf = nfields(x)
61,617✔
674
        for i in 1:nf
90,602✔
675
            if isdefined(x, i)
68,298✔
676
                serialize(s, getfield(x, i))
68,297✔
677
            else
678
                writetag(s.io, UNDEFREF_TAG)
1✔
679
            end
680
        end
68,297✔
681
    end
682
    nothing
61,643✔
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)
120✔
701
    io = s.io
120✔
702
    writetag(io, HEADER_TAG)
217✔
703
    write(io, "JL")  # magic bytes
120✔
704
    write(io, UInt8(ser_version))
217✔
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))
217✔
712
    write(io, [0x00,0x00,0x00]) # 3 reserved bytes
360✔
713
    nothing
120✔
714
end
715

716
function readheader(s::AbstractSerializer)
116✔
717
    # Tag already read
718
    io = s.io
116✔
719
    m1 = read(io, UInt8)
116✔
720
    m2 = read(io, UInt8)
116✔
721
    if m1 != UInt8('J') || m2 != UInt8('L')
232✔
722
        error("Unsupported serialization format (got header magic bytes $m1 $m2)")
×
723
    end
724
    version    = read(io, UInt8)
116✔
725
    flags      = read(io, UInt8)
116✔
726
    reserved1  = read(io, UInt8)
116✔
727
    reserved2  = read(io, UInt8)
116✔
728
    reserved3  = read(io, UInt8)
116✔
729
    endianflag = flags & 0x3
116✔
730
    wordflag   = (flags >> 2) & 0x3
116✔
731
    wordsize = wordflag == 0 ? 4 :
230✔
732
               wordflag == 1 ? 8 :
733
               error("Unknown word size flag in header")
734
    endian_bom = endianflag == 0 ? 0x04030201 :
117✔
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)))")
115✔
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
113✔
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
112✔
747
    return
112✔
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)
120✔
775
    ss = Serializer(s)
120✔
776
    writeheader(ss)
120✔
777
    serialize(ss, x)
120✔
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))
114✔
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)
803,648✔
814
    handle_deserialize(s, Int32(read(s.io, UInt8)::UInt8))
803,664✔
815
end
816

817
function deserialize_cycle(s::AbstractSerializer, @nospecialize(x))
5,417✔
818
    slot = pop!(s.pending_refs)
5,417✔
819
    s.table[slot] = x
5,417✔
820
    nothing
5,417✔
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))
43,999✔
829
    s.table[s.counter] = x
44,271✔
830
    s.counter += 1
44,271✔
831
    nothing
43,999✔
832
end
833

834
function gettable(s::AbstractSerializer, id::Int)
27,005✔
835
    get(s.table, id) do
27,665✔
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,113,154✔
851
    if b == 0
1,113,154✔
852
        return desertag(Int32(read(s.io, UInt8)::UInt8))
25,050✔
853
    end
854
    if b >= VALUE_TAGS
1,088,104✔
855
        return desertag(b)
311,913✔
856
    elseif b == TUPLE_TAG
776,191✔
857
        return deserialize_tuple(s, Int(read(s.io, UInt8)::UInt8))
10,112✔
858
    elseif b == SHORTBACKREF_TAG
766,079✔
859
        id = read(s.io, UInt16)::UInt16
27,664✔
860
        return gettable(s, Int(id))
27,664✔
861
    elseif b == BACKREF_TAG
738,415✔
862
        id = read(s.io, Int32)::Int32
1✔
863
        return gettable(s, Int(id))
1✔
864
    elseif b == ARRAY_TAG
738,414✔
865
        return deserialize_array(s)
9,038✔
866
    elseif b == DATATYPE_TAG
729,376✔
867
        return deserialize_datatype(s, false)
54,755✔
868
    elseif b == FULL_DATATYPE_TAG
674,621✔
869
        return deserialize_datatype(s, true)
261✔
870
    elseif b == WRAPPER_DATATYPE_TAG
674,360✔
871
        tname = deserialize(s)::Core.TypeName
5,069✔
872
        return unwrap_unionall(tname.wrapper)
5,065✔
873
    elseif b == OBJECT_TAG
669,291✔
874
        t = deserialize(s)
56,422✔
875
        if t === Missing
56,418✔
876
            return missing
×
877
        end
878
        return deserialize(s, t)
56,418✔
879
    elseif b == REF_OBJECT_TAG
612,869✔
880
        slot = s.counter; s.counter += 1
1,926✔
881
        push!(s.pending_refs, slot)
963✔
882
        t = deserialize(s)
963✔
883
        return deserialize(s, t)
962✔
884
    elseif b == SHARED_REF_TAG
611,906✔
885
        slot = s.counter; s.counter += 1
403,666✔
886
        obj = deserialize(s)
201,833✔
887
        s.table[slot] = obj
201,833✔
888
        return obj
201,833✔
889
    elseif b == SYMBOL_TAG
410,073✔
890
        return deserialize_symbol(s, Int(read(s.io, UInt8)::UInt8))
79,569✔
891
    elseif b == SHORTINT64_TAG
330,504✔
892
        return Int64(read(s.io, Int32)::Int32)
7,252✔
893
    elseif b == EXPR_TAG
323,252✔
894
        return deserialize_expr(s, Int(read(s.io, UInt8)::UInt8))
3,858✔
895
    elseif b == MODULE_TAG
319,394✔
896
        return deserialize_module(s)
57,945✔
897
    elseif b == STRING_TAG
261,449✔
898
        return deserialize_string(s, Int(read(s.io, UInt8)::UInt8))
202,903✔
899
    elseif b == LONGSTRING_TAG
58,546✔
900
        return deserialize_string(s, Int(read(s.io, Int64)::Int64))
41✔
901
    elseif b == SIMPLEVECTOR_TAG
58,505✔
902
        return deserialize_svec(s)
1,189✔
903
    elseif b == GLOBALREF_TAG
57,316✔
904
        return GlobalRef(deserialize(s)::Module, deserialize(s)::Symbol)
1,754✔
905
    elseif b == FULL_GLOBALREF_TAG
55,562✔
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
55,549✔
910
        return deserialize_tuple(s, Int(read(s.io, Int32)::Int32))
1✔
911
    elseif b == LONGEXPR_TAG
55,548✔
912
        return deserialize_expr(s, Int(read(s.io, Int32)::Int32))
1✔
913
    elseif b == LONGBACKREF_TAG
55,547✔
914
        id = read(s.io, Int64)::Int64
×
915
        return gettable(s, Int(id))
×
916
    elseif b == LONGSYMBOL_TAG
55,547✔
917
        return deserialize_symbol(s, Int(read(s.io, Int32)::Int32))
4✔
918
    elseif b == HEADER_TAG
55,543✔
919
        readheader(s)
116✔
920
        return deserialize(s)
112✔
921
    elseif b == INT8_TAG
55,427✔
922
        return read(s.io, Int8)
20✔
923
    elseif b == INT8_TAG+1
55,407✔
924
        return read(s.io, UInt8)
2,643✔
925
    elseif b == INT8_TAG+2
52,764✔
926
        return read(s.io, Int16)
12✔
927
    elseif b == INT8_TAG+3
52,752✔
928
        return read(s.io, UInt16)
406✔
929
    elseif b == INT32_TAG
52,346✔
930
        return read(s.io, Int32)
930✔
931
    elseif b == INT8_TAG+5
51,416✔
932
        return read(s.io, UInt32)
16✔
933
    elseif b == INT64_TAG
51,400✔
934
        return read(s.io, Int64)
171✔
935
    elseif b == INT8_TAG+7
51,229✔
936
        return read(s.io, UInt64)
1,153✔
937
    elseif b == INT8_TAG+8
50,076✔
938
        return read(s.io, Int128)
11,074✔
939
    elseif b == INT8_TAG+9
39,002✔
940
        return read(s.io, UInt128)
17,590✔
941
    elseif b == INT8_TAG+10
21,412✔
942
        return read(s.io, Float16)
4✔
943
    elseif b == INT8_TAG+11
21,408✔
944
        return read(s.io, Float32)
×
945
    elseif b == INT8_TAG+12
21,408✔
946
        return read(s.io, Float64)
527✔
947
    elseif b == INT8_TAG+13
20,881✔
948
        return read(s.io, Char)
11,137✔
949
    elseif b == IDDICT_TAG
9,744✔
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
9,742✔
956
    if ismutabletype(t) && length(t.types) > 0  # manual specialization of fieldcount
9,742✔
957
        slot = s.counter; s.counter += 1
8,914✔
958
        push!(s.pending_refs, slot)
4,457✔
959
    end
960
    return deserialize(s, t)
9,742✔
961
end
962

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

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

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

980
function deserialize_module(s::AbstractSerializer)
57,945✔
981
    mkey = deserialize(s)
57,945✔
982
    if isa(mkey, Tuple)
57,945✔
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)
57,945✔
993
        pkg = (mkey === nothing) ? Base.PkgId(name) : Base.PkgId(Base.UUID(mkey), name)
75,323✔
994
        m = Base.root_module(pkg)
57,945✔
995
        mname = deserialize(s)
57,945✔
996
        while mname !== ()
58,204✔
997
            m = getglobal(m, mname)::Module
261✔
998
            mname = deserialize(s)
259✔
999
        end
259✔
1000
    end
1001
    return m
57,943✔
1002
end
1003

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

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

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

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

1126
function deserialize(s::AbstractSerializer, ::Type{CodeInfo})
396✔
1127
    ci = ccall(:jl_new_code_info_uninit, Ref{CodeInfo}, ())
396✔
1128
    deserialize_cycle(s, ci)
396✔
1129
    code = deserialize(s)::Vector{Any}
396✔
1130
    ci.code = code
395✔
1131
    # allow older-style IR with return and gotoifnot Exprs
1132
    for i in 1:length(code)
790✔
1133
        stmt = code[i]
2,624✔
1134
        if isa(stmt, Expr)
2,624✔
1135
            ex = stmt::Expr
1,627✔
1136
            if ex.head === :return
1,627✔
1137
                code[i] = ReturnNode(isempty(ex.args) ? nothing : ex.args[1])
2✔
1138
            elseif ex.head === :gotoifnot
1,626✔
1139
                code[i] = GotoIfNot(ex.args[1], ex.args[2])
×
1140
            end
1141
        end
1142
    end
4,853✔
1143
    ci.codelocs = deserialize(s)::Vector{Int32}
395✔
1144
    _x = deserialize(s)
395✔
1145
    if _x isa Array || _x isa Int
790✔
1146
        pre_12 = false
394✔
1147
        ci.ssavaluetypes = _x
394✔
1148
    else
1149
        pre_12 = true
1✔
1150
        # < v1.2
1151
        ci.method_for_inference_limit_heuristics = _x
1✔
1152
        ci.ssavaluetypes = deserialize(s)
1✔
1153
        ci.linetable = deserialize(s)
1✔
1154
    end
1155
    ssaflags = deserialize(s)
395✔
1156
    if length(ssaflags) ≠ length(code)
395✔
1157
        # make sure the length of `ssaflags` matches that of `code`
1158
        # so that the latest inference doesn't throw on IRs serialized from old versions
1159
        ssaflags = UInt8[0x00 for _ in 1:length(code)]
3✔
1160
    end
1161
    ci.ssaflags = ssaflags
395✔
1162
    if pre_12
395✔
1163
        ci.slotflags = deserialize(s)
1✔
1164
    else
1165
        ci.method_for_inference_limit_heuristics = deserialize(s)
394✔
1166
        ci.linetable = deserialize(s)
394✔
1167
    end
1168
    ci.slotnames = deserialize(s)
395✔
1169
    if !pre_12
395✔
1170
        ci.slotflags = deserialize(s)
394✔
1171
        ci.slottypes = deserialize(s)
394✔
1172
        ci.rettype = deserialize(s)
394✔
1173
        ci.parent = deserialize(s)
394✔
1174
        world_or_edges = deserialize(s)
394✔
1175
        pre_13 = isa(world_or_edges, Integer)
394✔
1176
        if pre_13
394✔
1177
            ci.min_world = world_or_edges
×
1178
        else
1179
            ci.edges = world_or_edges
394✔
1180
            ci.min_world = reinterpret(UInt, deserialize(s))
394✔
1181
            ci.max_world = reinterpret(UInt, deserialize(s))
394✔
1182
        end
1183
    end
1184
    ci.inferred = deserialize(s)
395✔
1185
    if format_version(s) < 22
395✔
1186
        inlining_cost = deserialize(s)
1✔
1187
        if isa(inlining_cost, Bool)
1✔
1188
            Core.Compiler.set_inlineable!(ci, inlining_cost)
1✔
1189
        else
1190
            ci.inlining_cost = inlining_cost
×
1191
        end
1192
    end
1193
    ci.propagate_inbounds = deserialize(s)
395✔
1194
    ci.pure = deserialize(s)
395✔
1195
    if format_version(s) >= 20
395✔
1196
        ci.has_fcall = deserialize(s)
394✔
1197
    end
1198
    if format_version(s) >= 21
395✔
1199
        ci.inlining = deserialize(s)::UInt8
394✔
1200
    end
1201
    if format_version(s) >= 14
395✔
1202
        ci.constprop = deserialize(s)::UInt8
394✔
1203
    end
1204
    if format_version(s) >= 17
395✔
1205
        ci.purity = deserialize(s)::UInt8
394✔
1206
    end
1207
    if format_version(s) >= 22
395✔
1208
        ci.inlining_cost = deserialize(s)::UInt16
394✔
1209
    end
1210
    return ci
395✔
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,038✔
1220
    slot = s.counter; s.counter += 1
18,076✔
1221
    d1 = deserialize(s)
9,038✔
1222
    if isa(d1, Type)
9,038✔
1223
        elty = d1
8,233✔
1224
        d1 = deserialize(s)
8,233✔
1225
    else
1226
        elty = UInt8
794✔
1227
    end
1228
    if isa(d1, Int32) || isa(d1, Int64)
18,076✔
1229
        if elty !== Bool && isbitstype(elty)
9,199✔
1230
            a = Vector{elty}(undef, d1)
2,809✔
1231
            s.table[slot] = a
2,809✔
1232
            return read!(s.io, a)
2,809✔
1233
        end
1234
        dims = (Int(d1),)
12,330✔
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,466✔
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,177✔
1262
    s.table[slot] = A
6,177✔
1263
    sizehint!(s.table, s.counter + div(length(A)::Int,4))
6,217✔
1264
    deserialize_fillarray!(A, s)
6,177✔
1265
    return A
6,175✔
1266
end
1267

1268
function deserialize_fillarray!(A::Array{T}, s::AbstractSerializer) where {T}
6,177✔
1269
    for i = eachindex(A)
8,806✔
1270
        tag = Int32(read(s.io, UInt8)::UInt8)
252,609✔
1271
        if tag != UNDEFREF_TAG
252,609✔
1272
            @inbounds A[i] = handle_deserialize(s, tag)
252,607✔
1273
        end
1274
    end
502,587✔
1275
    return A
6,175✔
1276
end
1277

1278
function deserialize_expr(s::AbstractSerializer, len)
3,859✔
1279
    e = Expr(:temp)
3,859✔
1280
    resolve_ref_immediately(s, e)
3,859✔
1281
    e.head = deserialize(s)::Symbol
3,859✔
1282
    e.args = Any[ deserialize(s) for i = 1:len ]
9,146✔
1283
    e
3,859✔
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)
396✔
1294
    name = deserialize(s)::Symbol
396✔
1295
    tn = lookup_object_number(s, number)
398✔
1296
    if tn !== nothing
396✔
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
394✔
1301
        tn = ccall(:jl_new_typename_in, Any, (Any, Any, Cint, Cint),
394✔
1302
                   tn_name, __deserialized_types__, false, false)
1303
        makenew = true
394✔
1304
    end
1305
    tn = tn::Core.TypeName
396✔
1306
    remember_object(s, tn, number)
396✔
1307
    deserialize_cycle(s, tn)
396✔
1308

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

1320
    if makenew
396✔
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),
394✔
1325
                    tn, tn.module, super, parameters, names, types, attrs,
1326
                    abstr, mutabl, ninitialized)
1327
        @assert tn == ndt.name
394✔
1328
        ccall(:jl_set_const, Cvoid, (Any, Any, Any), tn.module, tn.name, tn.wrapper)
394✔
1329
        ty = tn.wrapper
394✔
1330
        tn.max_methods = maxm
394✔
1331
        if has_instance
394✔
1332
            ty = ty::DataType
337✔
1333
            if !Base.issingletontype(ty)
337✔
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)
396✔
1342
    if tag != UNDEFREF_TAG
396✔
1343
        mtname = handle_deserialize(s, tag)
395✔
1344
        defs = deserialize(s)
395✔
1345
        maxa = deserialize(s)::Int
394✔
1346
        if makenew
394✔
1347
            mt = ccall(:jl_new_method_table, Any, (Any, Any), name, tn.module)
392✔
1348
            if !isempty(parameters)
392✔
1349
                mt.offs = 0
53✔
1350
            end
1351
            mt.name = mtname
392✔
1352
            setfield!(mt, :max_args, maxa, :monotonic)
392✔
1353
            ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), tn, Base.fieldindex(Core.TypeName, :mt)-1, mt)
392✔
1354
            for def in defs
392✔
1355
                if isdefined(def, :sig)
392✔
1356
                    ccall(:jl_method_table_insert, Cvoid, (Any, Any, Ptr{Cvoid}), mt, def, C_NULL)
392✔
1357
                end
1358
            end
392✔
1359
        end
1360
        tag = Int32(read(s.io, UInt8)::UInt8)
394✔
1361
        if tag != UNDEFREF_TAG
394✔
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, f::$ty, args...) = $kws(kwargs, f, args...)
394✔
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
395✔
1380
end
1381

1382
function deserialize_datatype(s::AbstractSerializer, full::Bool)
55,016✔
1383
    slot = s.counter; s.counter += 1
110,032✔
1384
    if full
55,016✔
1385
        tname = deserialize(s)::Core.TypeName
261✔
1386
        ty = tname.wrapper
261✔
1387
    else
1388
        name = deserialize(s)::Symbol
54,755✔
1389
        mod = deserialize(s)::Module
54,755✔
1390
        ty = getglobal(mod, name)
54,755✔
1391
    end
1392
    if isa(ty,DataType) && isempty(ty.parameters)
55,012✔
1393
        t = ty
16,912✔
1394
    else
1395
        np = Int(read(s.io, Int32)::Int32)
38,100✔
1396
        if np == 0
38,100✔
1397
            t = unwrap_unionall(ty)
3✔
1398
        elseif ty === Tuple
38,097✔
1399
            # note np==0 has its own tag
1400
            if np == 1
1,675✔
1401
                t = Tuple{deserialize(s)}
1,060✔
1402
            elseif np == 2
615✔
1403
                t = Tuple{deserialize(s), deserialize(s)}
479✔
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,697✔
1410
            end
1411
        else
1412
            t = ty
36,416✔
1413
            for i = 1:np
72,844✔
1414
                t = t{deserialize(s)}
103,962✔
1415
            end
103,962✔
1416
        end
1417
    end
1418
    s.table[slot] = t
55,012✔
1419
    return t
55,012✔
1420
end
1421

1422
function deserialize(s::AbstractSerializer, ::Type{UnionAll})
64✔
1423
    form = read(s.io, UInt8)
64✔
1424
    if form == 0
64✔
1425
        var = deserialize(s)
2✔
1426
        body = deserialize(s)
2✔
1427
        return UnionAll(var, body)
2✔
1428
    else
1429
        n = read(s.io, Int16)
62✔
1430
        t = deserialize(s)::DataType
62✔
1431
        w = t.name.wrapper
62✔
1432
        k = 0
62✔
1433
        while isa(w, UnionAll)
157✔
1434
            w = w.body
95✔
1435
            k += 1
95✔
1436
        end
95✔
1437
        w = t.name.wrapper
62✔
1438
        k -= n
62✔
1439
        while k > 0
62✔
1440
            w = w.body
×
1441
            k -= 1
×
1442
        end
×
1443
        return w
62✔
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)
202,882✔
1476
    out = ccall(:jl_alloc_string, Ref{String}, (Csize_t,), len)
202,944✔
1477
    unsafe_read(s.io, pointer(out), len)
202,944✔
1478
    return out
202,944✔
1479
end
1480

1481
# default DataType deserializer
1482
function deserialize(s::AbstractSerializer, t::DataType)
60,661✔
1483
    nf = length(t.types)
60,661✔
1484
    if isprimitivetype(t)
60,661✔
1485
        return read(s.io, t)
26✔
1486
    elseif ismutabletype(t)
60,635✔
1487
        x = ccall(:jl_new_struct_uninit, Any, (Any,), t)
1,182✔
1488
        deserialize_cycle(s, x)
1,182✔
1489
        for i in 1:nf
2,362✔
1490
            tag = Int32(read(s.io, UInt8)::UInt8)
4,040✔
1491
            if tag != UNDEFREF_TAG
4,040✔
1492
                ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), x, i-1, handle_deserialize(s, tag))
3,587✔
1493
            end
1494
        end
6,900✔
1495
        return x
1,182✔
1496
    elseif nf == 0
59,453✔
1497
        return ccall(:jl_new_struct_uninit, Any, (Any,), t)
32,663✔
1498
    else
1499
        na = nf
26,790✔
1500
        vflds = Vector{Any}(undef, nf)
26,790✔
1501
        for i in 1:nf
53,580✔
1502
            tag = Int32(read(s.io, UInt8)::UInt8)
52,901✔
1503
            if tag != UNDEFREF_TAG
52,901✔
1504
                f = handle_deserialize(s, tag)
52,900✔
1505
                na >= i && (vflds[i] = f)
52,898✔
1506
            else
1507
                na >= i && (na = i - 1) # rest of tail must be undefined values
1✔
1508
            end
1509
        end
79,010✔
1510
        return ccall(:jl_new_structv, Any, (Any, Ptr{Any}, UInt32), t, vflds, na)
26,788✔
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)
152✔
1520
        v = deserialize(s)
152✔
1521
        t[k] = v
152✔
1522
    end
300✔
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)
1✔
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,208✔
1545
    serialize_type(s, typeof(frame))
1,208✔
1546
    serialize(s, frame.func)
1,208✔
1547
    serialize(s, frame.file)
1,208✔
1548
    write(s.io, frame.line)
1,208✔
1549
    write(s.io, frame.from_c)
1,209✔
1550
    write(s.io, frame.inlined)
1,209✔
1551
    write(s.io, frame.pointer)
1,208✔
1552
    nothing
1,208✔
1553
end
1554

1555
function deserialize(s::AbstractSerializer, ::Type{Base.StackTraces.StackFrame})
1,208✔
1556
    func = deserialize(s)
1,208✔
1557
    file = deserialize(s)
1,208✔
1558
    line = read(s.io, Int)
1,208✔
1559
    from_c = read(s.io, Bool)
1,208✔
1560
    inlined = read(s.io, Bool)
1,208✔
1561
    pointer = read(s.io, UInt64)
1,208✔
1562
    return Base.StackTraces.StackFrame(func, file, line, nothing, from_c, inlined, pointer)
1,208✔
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