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

JuliaLang / julia / #37638

01 Oct 2023 06:36PM UTC coverage: 87.461% (-0.1%) from 87.584%
#37638

push

local

web-flow
Update libc.jl compatability note (#51535)

Update libc.jl compatability note to julia 1.11

73897 of 84491 relevant lines covered (87.46%)

11729457.42 hits per line

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

92.08
/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)
215✔
27
end
28

29
Serializer(io::IO) = Serializer{typeof(io)}(io)
215✔
30

31
## serializing values ##
32

33
const n_int_literals = 33
34
const n_reserved_slots = 24
35
const n_reserved_tags = 8
36

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

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

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

74
    fill(:_reserved_, n_reserved_slots)...,
75

76
    (Int32(0):Int32(n_int_literals-1))...,
77
    (Int64(0):Int64(n_int_literals-1))...
78
]
79

80
const NTAGS = length(TAGS)
81
@assert NTAGS == 255
82

83
const ser_version = 25 # do not make changes without bumping the version #!
84

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

88
function sertag(@nospecialize(v))
410,258✔
89
    # NOTE: we use jl_value_ptr directly since we know at least one of the arguments
90
    # in the comparison below is a singleton.
91
    ptr = ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), v)
410,871✔
92
    ptags = convert(Ptr{Ptr{Cvoid}}, pointer(TAGS))
410,871✔
93
    # note: constant ints & reserved slots never returned here
94
    @inbounds for i in 1:(NTAGS-(n_reserved_slots+2*n_int_literals))
16,184,900✔
95
        ptr == unsafe_load(ptags,i) && return i%Int32
53,299,818✔
96
    end
106,009,885✔
97
    return Int32(-1)
231,991✔
98
end
99
desertag(i::Int32) = @inbounds(TAGS[i])
345,964✔
100

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

145
writetag(s::IO, tag) = (write(s, UInt8(tag)); nothing)
1,816,122✔
146

147
function write_as_tag(s::IO, tag)
188,349✔
148
    tag < VALUE_TAGS && write(s, UInt8(0))
188,607✔
149
    write(s, UInt8(tag))
211,829✔
150
    nothing
188,447✔
151
end
152

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

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

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

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

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

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

194
function serialize(s::AbstractSerializer, t::Tuple)
11,717✔
195
    l = length(t)
11,717✔
196
    if l <= NTAGS
11,717✔
197
        writetag(s.io, TUPLE_TAG)
11,716✔
198
        write(s.io, UInt8(l))
11,743✔
199
    else
200
        writetag(s.io, LONGTUPLE_TAG)
1✔
201
        write(s.io, Int32(l))
1✔
202
    end
203
    for x in t
11,717✔
204
        serialize(s, x)
29,381✔
205
    end
22,029✔
206
end
207

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

216
function serialize(s::AbstractSerializer, x::Symbol)
133,608✔
217
    tag = sertag(x)
21,366,009✔
218
    if tag > 0
133,608✔
219
        return write_as_tag(s.io, tag)
45,200✔
220
    end
221
    pname = unsafe_convert(Ptr{UInt8}, x)
88,408✔
222
    len = Int(ccall(:strlen, Csize_t, (Cstring,), pname))
88,408✔
223
    if len > 7
88,408✔
224
        serialize_cycle(s, x) && return
48,608✔
225
    end
226
    if len <= NTAGS
81,885✔
227
        writetag(s.io, SYMBOL_TAG)
81,881✔
228
        write(s.io, UInt8(len))
82,148✔
229
    else
230
        writetag(s.io, LONGSYMBOL_TAG)
4✔
231
        write(s.io, Int32(len))
4✔
232
    end
233
    unsafe_write(s.io, pname, len)
81,885✔
234
    nothing
81,885✔
235
end
236

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

258
function serialize(s::AbstractSerializer, a::Array)
6,500✔
259
    serialize_cycle(s, a) && return
6,500✔
260
    elty = eltype(a)
6,498✔
261
    writetag(s.io, ARRAY_TAG)
6,498✔
262
    if elty !== UInt8
6,498✔
263
        serialize(s, elty)
6,110✔
264
    end
265
    if ndims(a) != 1
6,498✔
266
        serialize(s, size(a))
64✔
267
    else
268
        serialize(s, length(a))
6,434✔
269
    end
270
    if isbitstype(elty)
6,498✔
271
        serialize_array_data(s.io, a)
2,901✔
272
    else
273
        sizehint!(s.table, div(length(a),4))  # prepare for lots of pointers
3,632✔
274
        @inbounds for i in eachindex(a)
6,029✔
275
            if isassigned(a, i)
254,498✔
276
                serialize(s, a[i])
255,575✔
277
            else
278
                writetag(s.io, UNDEFREF_TAG)
2✔
279
            end
280
        end
254,498✔
281
    end
282
end
283

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

291
function serialize(s::AbstractSerializer, ss::String)
205,077✔
292
    len = sizeof(ss)
205,077✔
293
    if len > 7
205,077✔
294
        serialize_cycle(s, ss) && return
203,362✔
295
        writetag(s.io, SHARED_REF_TAG)
201,942✔
296
    end
297
    if len <= NTAGS
203,657✔
298
        writetag(s.io, STRING_TAG)
203,569✔
299
        write(s.io, UInt8(len))
203,591✔
300
    else
301
        writetag(s.io, LONGSTRING_TAG)
88✔
302
        write(s.io, Int64(len))
88✔
303
    end
304
    write(s.io, ss)
203,657✔
305
    nothing
203,657✔
306
end
307

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

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

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

326
function serialize(s::AbstractSerializer, ex::Expr)
3,467✔
327
    serialize_cycle(s, ex) && return
3,467✔
328
    l = length(ex.args)
3,467✔
329
    if l <= NTAGS
3,467✔
330
        writetag(s.io, EXPR_TAG)
3,466✔
331
        write(s.io, UInt8(l))
3,786✔
332
    else
333
        writetag(s.io, LONGEXPR_TAG)
1✔
334
        write(s.io, Int32(l))
1✔
335
    end
336
    serialize(s, ex.head)
3,467✔
337
    for a in ex.args
3,469✔
338
        serialize(s, a)
8,359✔
339
    end
8,359✔
340
end
341

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

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

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

362
function serialize_mod_names(s::AbstractSerializer, m::Module)
60,445✔
363
    p = parentmodule(m)
60,445✔
364
    if p === m || m === Base
80,180✔
365
        key = Base.root_module_key(m)
60,238✔
366
        uuid = key.uuid
60,238✔
367
        serialize(s, uuid === nothing ? nothing : uuid.value)
79,511✔
368
        serialize(s, Symbol(key.name))
60,238✔
369
    else
370
        serialize_mod_names(s, p)
207✔
371
        serialize(s, nameof(m))
207✔
372
    end
373
end
374

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

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

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

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

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

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

408
function serialize(s::AbstractSerializer, meth::Method)
371✔
409
    serialize_cycle(s, meth) && return
371✔
410
    writetag(s.io, METHOD_TAG)
371✔
411
    write(s.io, object_number(s, meth))
620✔
412
    serialize(s, meth.module)
371✔
413
    serialize(s, meth.name)
371✔
414
    serialize(s, meth.file)
371✔
415
    serialize(s, meth.line)
371✔
416
    serialize(s, meth.sig)
371✔
417
    serialize(s, meth.slot_syms)
371✔
418
    serialize(s, meth.nargs)
371✔
419
    serialize(s, meth.isva)
742✔
420
    serialize(s, meth.is_for_opaque_closure)
742✔
421
    serialize(s, meth.nospecializeinfer)
742✔
422
    serialize(s, meth.constprop)
371✔
423
    serialize(s, meth.purity)
371✔
424
    if isdefined(meth, :source)
371✔
425
        serialize(s, Base._uncompressed_ast(meth, meth.source))
387✔
426
    else
427
        serialize(s, nothing)
×
428
    end
429
    if isdefined(meth, :generator)
371✔
430
        serialize(s, meth.generator)
×
431
    else
432
        serialize(s, nothing)
371✔
433
    end
434
    if isdefined(meth, :recursion_relation)
371✔
435
        serialize(s, method.recursion_relation)
×
436
    else
437
        serialize(s, nothing)
371✔
438
    end
439
    if isdefined(meth, :external_mt)
371✔
440
        error("cannot serialize Method objects with external method tables")
×
441
    end
442
    nothing
371✔
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)
3✔
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,605✔
482
    if (g.mod === __deserialized_types__ ) ||
3,209✔
483
        (g.mod === Main && isdefined(g.mod, g.name) && isconst(g.mod, g.name))
484

485
        v = getglobal(g.mod, g.name)
450✔
486
        unw = unwrap_unionall(v)
450✔
487
        if isa(unw,DataType) && v === unw.name.wrapper && should_send_whole_type(s, unw)
478✔
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)
13✔
491
            serialize(s, v)
13✔
492
            return
13✔
493
        end
494
    end
495
    writetag(s.io, GLOBALREF_TAG)
1,592✔
496
    serialize(s, g.mod)
1,592✔
497
    serialize(s, g.name)
1,592✔
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)
8✔
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)
371✔
508
    serialize(s, t.name)
371✔
509
    serialize(s, t.names)
371✔
510
    primary = unwrap_unionall(t.wrapper)
371✔
511
    serialize(s, primary.super)
371✔
512
    serialize(s, primary.parameters)
371✔
513
    serialize(s, primary.types)
371✔
514
    serialize(s, isdefined(primary, :instance))
436✔
515
    serialize(s, t.flags & 0x1 == 0x1) # .abstract
742✔
516
    serialize(s, t.flags & 0x2 == 0x2) # .mutable
742✔
517
    serialize(s, Int32(length(primary.types) - t.n_uninitialized))
371✔
518
    serialize(s, t.max_methods)
371✔
519
    if isdefined(t, :mt) && t.mt !== Symbol.name.mt
371✔
520
        serialize(s, t.mt.name)
370✔
521
        serialize(s, collect(Base.MethodList(t.mt)))
740✔
522
        serialize(s, t.mt.max_args)
370✔
523
        kws = collect(methods(Core.kwcall, (Any, t.wrapper, Vararg)))
371✔
524
        if isempty(kws)
370✔
525
            writetag(s.io, UNDEFREF_TAG)
369✔
526
        else
527
            serialize(s, kws)
371✔
528
        end
529
    else
530
        writetag(s.io, UNDEFREF_TAG)
1✔
531
    end
532
    nothing
371✔
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)
80,154✔
537
    tn = t.name
80,180✔
538
    if isdefined(tn, :mt)
80,180✔
539
        # TODO improve somehow
540
        # send whole type for anonymous functions in Main
541
        name = tn.mt.name
79,809✔
542
        mod = tn.module
79,809✔
543
        isanonfunction = mod === Main && # only Main
80,089✔
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,528✔
551
    end
552
    return false
371✔
553
end
554

555
function serialize_type_data(s, @nospecialize(t::DataType))
80,151✔
556
    whole = should_send_whole_type(s, t)
159,842✔
557
    iswrapper = (t === unwrap_unionall(t.name.wrapper))
80,151✔
558
    if whole && iswrapper
80,151✔
559
        writetag(s.io, WRAPPER_DATATYPE_TAG)
1,305✔
560
        serialize(s, t.name)
1,305✔
561
        return
1,305✔
562
    end
563
    serialize_cycle(s, t) && return
78,846✔
564
    if whole
57,515✔
565
        writetag(s.io, FULL_DATATYPE_TAG)
253✔
566
        serialize(s, t.name)
253✔
567
    else
568
        writetag(s.io, DATATYPE_TAG)
57,262✔
569
        serialize(s, nameof(t))
57,262✔
570
        serialize(s, parentmodule(t))
57,262✔
571
    end
572
    if !isempty(t.parameters)
57,515✔
573
        if iswrapper
39,426✔
574
            write(s.io, Int32(0))
4✔
575
        else
576
            write(s.io, Int32(length(t.parameters)))
39,422✔
577
            for p in t.parameters
78,844✔
578
                serialize(s, p)
104,813✔
579
            end
104,813✔
580
        end
581
    end
582
    nothing
57,515✔
583
end
584

585
function serialize(s::AbstractSerializer, t::DataType)
80,590✔
586
    tag = sertag(t)
6,402,799✔
587
    tag > 0 && return write_as_tag(s.io, tag)
80,590✔
588
    if t === Tuple
22,030✔
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,030✔
596
end
597

598
function serialize_type(s::AbstractSerializer, @nospecialize(t::DataType), ref::Bool = false)
65,144✔
599
    tag = sertag(t)
9,859,120✔
600
    tag > 0 && return writetag(s.io, tag)
64,317✔
601
    writetag(s.io, ref ? REF_OBJECT_TAG : OBJECT_TAG)
58,119✔
602
    serialize_type_data(s, t)
58,119✔
603
end
604

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

615
function serialize(s::AbstractSerializer, n::Int64)
51,380✔
616
    if 0 <= n <= (n_int_literals-1)
51,380✔
617
        write(s.io, UInt8(ZERO64_TAG+n))
39,948✔
618
    elseif typemin(Int32) <= n <= typemax(Int32)
12,013✔
619
        writetag(s.io, SHORTINT64_TAG)
11,891✔
620
        write(s.io, Int32(n))
11,891✔
621
    else
622
        writetag(s.io, INT64_TAG)
122✔
623
        write(s.io, n)
122✔
624
    end
625
    nothing
51,380✔
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)
139,037✔
633
end
634

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

637
function serialize(s::AbstractSerializer, u::UnionAll)
71✔
638
    writetag(s.io, UNIONALL_TAG)
71✔
639
    n = 0; t = u
142✔
640
    while isa(t, UnionAll)
183✔
641
        t = t.body
112✔
642
        n += 1
112✔
643
    end
112✔
644
    if isa(t, DataType) && t === unwrap_unionall(t.name.wrapper)
71✔
645
        write(s.io, UInt8(1))
78✔
646
        write(s.io, Int16(n))
69✔
647
        serialize(s, t)
69✔
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)
132,303✔
656

657
function serialize_any(s::AbstractSerializer, @nospecialize(x))
132,325✔
658
    tag = sertag(x)
15,903,542✔
659
    if tag > 0
132,325✔
660
        return write_as_tag(s.io, tag)
68,891✔
661
    end
662
    t = typeof(x)::DataType
63,434✔
663
    if isprimitivetype(t)
63,434✔
664
        serialize_type(s, t)
12✔
665
        write(s.io, x)
12✔
666
    else
667
        if ismutable(x)
63,422✔
668
            serialize_cycle(s, x) && return
3,218✔
669
            serialize_type(s, t, true)
3,109✔
670
        else
671
            serialize_type(s, t, false)
60,204✔
672
        end
673
        nf = nfields(x)
63,313✔
674
        for i in 1:nf
95,213✔
675
            if isdefined(x, i)
79,937✔
676
                serialize(s, getfield(x, i))
79,936✔
677
            else
678
                writetag(s.io, UNDEFREF_TAG)
1✔
679
            end
680
        end
79,937✔
681
    end
682
    nothing
63,325✔
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)
113✔
701
    io = s.io
113✔
702
    writetag(io, HEADER_TAG)
113✔
703
    write(io, "JL")  # magic bytes
113✔
704
    write(io, UInt8(ser_version))
209✔
705
    endianness = (ENDIAN_BOM == 0x04030201 ? 0 :
100✔
706
                  ENDIAN_BOM == 0x01020304 ? 1 :
707
                  error("unsupported endianness in serializer"))
708
    machine = (sizeof(Int) == 4 ? 0 :
100✔
709
               sizeof(Int) == 8 ? 1 :
710
               error("unsupported word size in serializer"))
711
    write(io, UInt8(endianness) | (UInt8(machine) << 2))
209✔
712
    write(io, [0x00,0x00,0x00]) # 3 reserved bytes
339✔
713
    nothing
113✔
714
end
715

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

817
function deserialize_cycle(s::AbstractSerializer, @nospecialize(x))
4,716✔
818
    slot = pop!(s.pending_refs)
4,716✔
819
    s.table[slot] = x
4,716✔
820
    nothing
4,716✔
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))
45,241✔
829
    s.table[s.counter] = x
45,243✔
830
    s.counter += 1
45,243✔
831
    nothing
45,241✔
832
end
833

834
function gettable(s::AbstractSerializer, id::Int)
29,805✔
835
    get(s.table, id) do
29,805✔
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,123,666✔
851
    if b == 0
1,123,666✔
852
        return desertag(Int32(read(s.io, UInt8)::UInt8))
22,653✔
853
    end
854
    if b >= VALUE_TAGS
1,101,013✔
855
        return desertag(b)
315,634✔
856
    elseif b == TUPLE_TAG
785,379✔
857
        return deserialize_tuple(s, Int(read(s.io, UInt8)::UInt8))
11,645✔
858
    elseif b == SHORTBACKREF_TAG
773,734✔
859
        id = read(s.io, UInt16)::UInt16
29,804✔
860
        return gettable(s, Int(id))
29,804✔
861
    elseif b == BACKREF_TAG
743,930✔
862
        id = read(s.io, Int32)::Int32
1✔
863
        return gettable(s, Int(id))
1✔
864
    elseif b == ARRAY_TAG
743,929✔
865
        return deserialize_array(s)
6,500✔
866
    elseif b == DATATYPE_TAG
737,429✔
867
        return deserialize_datatype(s, false)
57,200✔
868
    elseif b == FULL_DATATYPE_TAG
680,229✔
869
        return deserialize_datatype(s, true)
264✔
870
    elseif b == WRAPPER_DATATYPE_TAG
679,965✔
871
        tname = deserialize(s)::Core.TypeName
1,308✔
872
        return unwrap_unionall(tname.wrapper)
1,304✔
873
    elseif b == OBJECT_TAG
678,657✔
874
        t = deserialize(s)
55,443✔
875
        if t === Missing
55,439✔
876
            return missing
×
877
        end
878
        return deserialize(s, t)
55,439✔
879
    elseif b == REF_OBJECT_TAG
623,214✔
880
        slot = s.counter; s.counter += 1
5,256✔
881
        push!(s.pending_refs, slot)
2,628✔
882
        t = deserialize(s)
2,628✔
883
        return deserialize(s, t)
2,627✔
884
    elseif b == SHARED_REF_TAG
620,586✔
885
        slot = s.counter; s.counter += 1
403,778✔
886
        obj = deserialize(s)
201,889✔
887
        s.table[slot] = obj
201,889✔
888
        return obj
201,889✔
889
    elseif b == SYMBOL_TAG
418,697✔
890
        return deserialize_symbol(s, Int(read(s.io, UInt8)::UInt8))
81,596✔
891
    elseif b == SHORTINT64_TAG
337,101✔
892
        return Int64(read(s.io, Int32)::Int32)
11,878✔
893
    elseif b == EXPR_TAG
325,223✔
894
        return deserialize_expr(s, Int(read(s.io, UInt8)::UInt8))
3,334✔
895
    elseif b == MODULE_TAG
321,889✔
896
        return deserialize_module(s)
60,184✔
897
    elseif b == STRING_TAG
261,705✔
898
        return deserialize_string(s, Int(read(s.io, UInt8)::UInt8))
203,494✔
899
    elseif b == LONGSTRING_TAG
58,211✔
900
        return deserialize_string(s, Int(read(s.io, Int64)::Int64))
88✔
901
    elseif b == SIMPLEVECTOR_TAG
58,123✔
902
        return deserialize_svec(s)
1,120✔
903
    elseif b == GLOBALREF_TAG
57,003✔
904
        return GlobalRef(deserialize(s)::Module, deserialize(s)::Symbol)
1,597✔
905
    elseif b == FULL_GLOBALREF_TAG
55,406✔
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,393✔
910
        return deserialize_tuple(s, Int(read(s.io, Int32)::Int32))
1✔
911
    elseif b == LONGEXPR_TAG
55,392✔
912
        return deserialize_expr(s, Int(read(s.io, Int32)::Int32))
1✔
913
    elseif b == LONGBACKREF_TAG
55,391✔
914
        id = read(s.io, Int64)::Int64
×
915
        return gettable(s, Int(id))
×
916
    elseif b == LONGSYMBOL_TAG
55,391✔
917
        return deserialize_symbol(s, Int(read(s.io, Int32)::Int32))
4✔
918
    elseif b == HEADER_TAG
55,387✔
919
        readheader(s)
103✔
920
        return deserialize(s)
99✔
921
    elseif b == INT8_TAG
55,284✔
922
        return read(s.io, Int8)
20✔
923
    elseif b == INT8_TAG+1
55,264✔
924
        return read(s.io, UInt8)
2,505✔
925
    elseif b == INT8_TAG+2
52,759✔
926
        return read(s.io, Int16)
12✔
927
    elseif b == INT8_TAG+3
52,747✔
928
        return read(s.io, UInt16)
383✔
929
    elseif b == INT32_TAG
52,364✔
930
        return read(s.io, Int32)
1,198✔
931
    elseif b == INT8_TAG+5
51,166✔
932
        return read(s.io, UInt32)
15✔
933
    elseif b == INT64_TAG
51,151✔
934
        return read(s.io, Int64)
130✔
935
    elseif b == INT8_TAG+7
51,021✔
936
        return read(s.io, UInt64)
1,109✔
937
    elseif b == INT8_TAG+8
49,912✔
938
        return read(s.io, Int128)
11,074✔
939
    elseif b == INT8_TAG+9
38,838✔
940
        return read(s.io, UInt128)
19,505✔
941
    elseif b == INT8_TAG+10
19,333✔
942
        return read(s.io, Float16)
4✔
943
    elseif b == INT8_TAG+11
19,329✔
944
        return read(s.io, Float32)
×
945
    elseif b == INT8_TAG+12
19,329✔
946
        return read(s.io, Float64)
513✔
947
    elseif b == INT8_TAG+13
18,816✔
948
        return read(s.io, Char)
11,137✔
949
    elseif b == IDDICT_TAG
7,679✔
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
7,677✔
956
    if ismutabletype(t) && length(t.types) > 0  # manual specialization of fieldcount
7,677✔
957
        slot = s.counter; s.counter += 1
4,182✔
958
        push!(s.pending_refs, slot)
2,091✔
959
    end
960
    return deserialize(s, t)
7,677✔
961
end
962

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

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

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

980
function deserialize_module(s::AbstractSerializer)
60,184✔
981
    mkey = deserialize(s)
60,184✔
982
    if isa(mkey, Tuple)
60,184✔
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)
60,184✔
993
        pkg = (mkey === nothing) ? Base.PkgId(name) : Base.PkgId(Base.UUID(mkey), name)
79,464✔
994
        m = Base.root_module(pkg)
60,184✔
995
        mname = deserialize(s)
60,184✔
996
        while mname !== ()
60,388✔
997
            m = getglobal(m, mname)::Module
206✔
998
            mname = deserialize(s)
204✔
999
        end
204✔
1000
    end
1001
    return m
60,182✔
1002
end
1003

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

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

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

1121
function deserialize(s::AbstractSerializer, ::Type{PhiNode})
×
1122
    edges = deserialize(s)
×
1123
    if edges isa Vector{Any}
×
1124
        edges = Vector{Int32}(edges)
×
1125
    end
1126
    values = deserialize(s)::Vector{Any}
×
1127
    return PhiNode(edges, values)
×
1128
end
1129

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

1224
if Int === Int64
1225
const OtherInt = Int32
1226
else
1227
const OtherInt = Int64
1228
end
1229

1230
function deserialize_array(s::AbstractSerializer)
6,500✔
1231
    slot = s.counter; s.counter += 1
13,000✔
1232
    d1 = deserialize(s)
6,500✔
1233
    if isa(d1, Type)
6,500✔
1234
        elty = d1
6,123✔
1235
        d1 = deserialize(s)
6,123✔
1236
    else
1237
        elty = UInt8
377✔
1238
    end
1239
    if isa(d1, Int32) || isa(d1, Int64)
13,000✔
1240
        if elty !== Bool && isbitstype(elty)
6,665✔
1241
            a = Vector{elty}(undef, d1)
2,820✔
1242
            s.table[slot] = a
2,820✔
1243
            return read!(s.io, a)
2,820✔
1244
        end
1245
        dims = (Int(d1),)
7,232✔
1246
    elseif d1 isa Dims
64✔
1247
        dims = d1::Dims
64✔
1248
    else
1249
        dims = convert(Dims, d1::Tuple{Vararg{OtherInt}})::Dims
×
1250
    end
1251
    if isbitstype(elty)
3,921✔
1252
        n = prod(dims)::Int
104✔
1253
        if elty === Bool && n > 0
52✔
1254
            A = Array{Bool, length(dims)}(undef, dims)
1✔
1255
            i = 1
1✔
1256
            while i <= n
6✔
1257
                b = read(s.io, UInt8)::UInt8
5✔
1258
                v = (b >> 7) != 0
5✔
1259
                count = b & 0x7f
5✔
1260
                nxt = i + count
5✔
1261
                while i < nxt
14✔
1262
                    A[i] = v
9✔
1263
                    i += 1
9✔
1264
                end
9✔
1265
            end
6✔
1266
        else
1267
            A = read!(s.io, Array{elty}(undef, dims))
51✔
1268
        end
1269
        s.table[slot] = A
52✔
1270
        return A
52✔
1271
    end
1272
    A = Array{elty, length(dims)}(undef, dims)
3,628✔
1273
    s.table[slot] = A
3,628✔
1274
    sizehint!(s.table, s.counter + div(length(A)::Int,4))
3,679✔
1275
    deserialize_fillarray!(A, s)
3,628✔
1276
    return A
3,626✔
1277
end
1278

1279
function deserialize_fillarray!(A::Array{T}, s::AbstractSerializer) where {T}
3,628✔
1280
    for i = eachindex(A)
6,070✔
1281
        tag = Int32(read(s.io, UInt8)::UInt8)
254,506✔
1282
        if tag != UNDEFREF_TAG
254,506✔
1283
            @inbounds A[i] = handle_deserialize(s, tag)
254,504✔
1284
        end
1285
    end
506,568✔
1286
    return A
3,626✔
1287
end
1288

1289
function deserialize_expr(s::AbstractSerializer, len)
3,335✔
1290
    e = Expr(:temp)
3,335✔
1291
    resolve_ref_immediately(s, e)
3,335✔
1292
    e.head = deserialize(s)::Symbol
3,335✔
1293
    e.args = Any[ deserialize(s) for i = 1:len ]
7,958✔
1294
    e
3,335✔
1295
end
1296

1297
module __deserialized_types__ end
1298

1299
function deserialize(s::AbstractSerializer, ::Type{Core.TypeName})
9✔
1300
    number = read(s.io, UInt64)
9✔
1301
    return deserialize_typename(s, number)
9✔
1302
end
1303

1304
function deserialize_typename(s::AbstractSerializer, number)
373✔
1305
    name = deserialize(s)::Symbol
373✔
1306
    tn = lookup_object_number(s, number)
375✔
1307
    if tn !== nothing
373✔
1308
        makenew = false
2✔
1309
    else
1310
        # reuse the same name for the type, if possible, for nicer debugging
1311
        tn_name = isdefined(__deserialized_types__, name) ? gensym() : name
371✔
1312
        tn = ccall(:jl_new_typename_in, Any, (Any, Any, Cint, Cint),
371✔
1313
                   tn_name, __deserialized_types__, false, false)
1314
        makenew = true
371✔
1315
    end
1316
    tn = tn::Core.TypeName
373✔
1317
    remember_object(s, tn, number)
373✔
1318
    deserialize_cycle(s, tn)
373✔
1319

1320
    names = deserialize(s)::SimpleVector
373✔
1321
    super = deserialize(s)::Type
373✔
1322
    parameters = deserialize(s)::SimpleVector
373✔
1323
    types = deserialize(s)::SimpleVector
373✔
1324
    attrs = Core.svec()
373✔
1325
    has_instance = deserialize(s)::Bool
373✔
1326
    abstr = deserialize(s)::Bool
373✔
1327
    mutabl = deserialize(s)::Bool
373✔
1328
    ninitialized = deserialize(s)::Int32
373✔
1329
    maxm = format_version(s) >= 18 ? deserialize(s)::UInt8 : UInt8(0)
373✔
1330

1331
    if makenew
373✔
1332
        # TODO: there's an unhanded cycle in the dependency graph at this point:
1333
        # while deserializing super and/or types, we may have encountered
1334
        # tn.wrapper and throw UndefRefException before we get to this point
1335
        ndt = ccall(:jl_new_datatype, Any, (Any, Any, Any, Any, Any, Any, Any, Cint, Cint, Cint),
371✔
1336
                    tn, tn.module, super, parameters, names, types, attrs,
1337
                    abstr, mutabl, ninitialized)
1338
        @assert tn == ndt.name
371✔
1339
        ccall(:jl_set_const, Cvoid, (Any, Any, Any), tn.module, tn.name, tn.wrapper)
371✔
1340
        ty = tn.wrapper
371✔
1341
        tn.max_methods = maxm
371✔
1342
        if has_instance
371✔
1343
            ty = ty::DataType
305✔
1344
            if !Base.issingletontype(ty)
305✔
1345
                singleton = ccall(:jl_new_struct, Any, (Any, Any...), ty)
×
1346
                # use setfield! directly to avoid `fieldtype` lowering expecting to see a Singleton object already on ty
1347
                ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), ty, Base.fieldindex(DataType, :instance)-1, singleton)
×
1348
            end
1349
        end
1350
    end
1351

1352
    tag = Int32(read(s.io, UInt8)::UInt8)
373✔
1353
    if tag != UNDEFREF_TAG
373✔
1354
        mtname = handle_deserialize(s, tag)
372✔
1355
        defs = deserialize(s)
372✔
1356
        maxa = deserialize(s)::Int
371✔
1357
        if makenew
371✔
1358
            mt = ccall(:jl_new_method_table, Any, (Any, Any), name, tn.module)
369✔
1359
            if !isempty(parameters)
369✔
1360
                mt.offs = 0
60✔
1361
            end
1362
            mt.name = mtname
369✔
1363
            setfield!(mt, :max_args, maxa, :monotonic)
369✔
1364
            ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), tn, Base.fieldindex(Core.TypeName, :mt)-1, mt)
369✔
1365
            for def in defs
369✔
1366
                if isdefined(def, :sig)
369✔
1367
                    ccall(:jl_method_table_insert, Cvoid, (Any, Any, Ptr{Cvoid}), mt, def, C_NULL)
369✔
1368
                end
1369
            end
369✔
1370
        end
1371
        tag = Int32(read(s.io, UInt8)::UInt8)
371✔
1372
        if tag != UNDEFREF_TAG
371✔
1373
            kws = handle_deserialize(s, tag)
1✔
1374
            if makenew
1✔
1375
                if kws isa Vector{Method}
1✔
1376
                    for def in kws
1✔
1377
                        kwmt = typeof(Core.kwcall).name.mt
1✔
1378
                        ccall(:jl_method_table_insert, Cvoid, (Any, Any, Ptr{Cvoid}), mt, def, C_NULL)
1✔
1379
                    end
2✔
1380
                else
1381
                    # old object format -- try to forward from old to new
1382
                    @eval Core.kwcall(kwargs::NamedTuple, f::$ty, args...) = $kws(kwargs, f, args...)
371✔
1383
                end
1384
            end
1385
        end
1386
    elseif makenew
1✔
1387
        mt = Symbol.name.mt
1✔
1388
        ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), tn, Base.fieldindex(Core.TypeName, :mt)-1, mt)
1✔
1389
    end
1390
    return tn
372✔
1391
end
1392

1393
function deserialize_datatype(s::AbstractSerializer, full::Bool)
57,464✔
1394
    slot = s.counter; s.counter += 1
114,928✔
1395
    if full
57,464✔
1396
        tname = deserialize(s)::Core.TypeName
264✔
1397
        ty = tname.wrapper
264✔
1398
    else
1399
        name = deserialize(s)::Symbol
57,200✔
1400
        mod = deserialize(s)::Module
57,200✔
1401
        ty = getglobal(mod, name)
57,200✔
1402
    end
1403
    if isa(ty,DataType) && isempty(ty.parameters)
57,460✔
1404
        t = ty
18,091✔
1405
    else
1406
        np = Int(read(s.io, Int32)::Int32)
39,369✔
1407
        if np == 0
39,369✔
1408
            t = unwrap_unionall(ty)
4✔
1409
        elseif ty === Tuple
39,365✔
1410
            # note np==0 has its own tag
1411
            if np == 1
1,676✔
1412
                t = Tuple{deserialize(s)}
1,085✔
1413
            elseif np == 2
591✔
1414
                t = Tuple{deserialize(s), deserialize(s)}
467✔
1415
            elseif np == 3
124✔
1416
                t = Tuple{deserialize(s), deserialize(s), deserialize(s)}
85✔
1417
            elseif np == 4
39✔
1418
                t = Tuple{deserialize(s), deserialize(s), deserialize(s), deserialize(s)}
17✔
1419
            else
1420
                t = Tuple{Any[ deserialize(s) for i=1:np ]...}
1,698✔
1421
            end
1422
        else
1423
            t = ty
37,689✔
1424
            for i = 1:np
75,378✔
1425
                t = t{deserialize(s)}
102,221✔
1426
            end
102,221✔
1427
        end
1428
    end
1429
    s.table[slot] = t
57,460✔
1430
    return t
57,460✔
1431
end
1432

1433
function deserialize(s::AbstractSerializer, ::Type{UnionAll})
72✔
1434
    form = read(s.io, UInt8)
72✔
1435
    if form == 0
72✔
1436
        var = deserialize(s)
2✔
1437
        body = deserialize(s)
2✔
1438
        return UnionAll(var, body)
2✔
1439
    else
1440
        n = read(s.io, Int16)
70✔
1441
        t = deserialize(s)::DataType
70✔
1442
        w = t.name.wrapper
70✔
1443
        k = 0
70✔
1444
        while isa(w, UnionAll)
182✔
1445
            w = w.body
112✔
1446
            k += 1
112✔
1447
        end
112✔
1448
        w = t.name.wrapper
70✔
1449
        k -= n
70✔
1450
        while k > 0
70✔
1451
            w = w.body
×
1452
            k -= 1
×
1453
        end
×
1454
        return w
70✔
1455
    end
1456
end
1457

1458
function deserialize(s::AbstractSerializer, ::Type{Task})
3✔
1459
    t = Task(()->nothing)
3✔
1460
    deserialize_cycle(s, t)
3✔
1461
    t.code = deserialize(s)
3✔
1462
    t.storage = deserialize(s)
3✔
1463
    state = deserialize(s)
3✔
1464
    if state === :runnable
3✔
1465
        t._state = Base.task_state_runnable
×
1466
    elseif state === :done
3✔
1467
        t._state = Base.task_state_done
1✔
1468
    elseif state === :failed
2✔
1469
        t._state = Base.task_state_failed
2✔
1470
    else
1471
        @assert false
×
1472
    end
1473
    t.result = deserialize(s)
3✔
1474
    exc = deserialize(s)
3✔
1475
    if exc === nothing
3✔
1476
        t._isexception = false
×
1477
    elseif exc isa Bool
3✔
1478
        t._isexception = exc
3✔
1479
    else
1480
        t._isexception = true
×
1481
        t.result = exc
×
1482
    end
1483
    t
3✔
1484
end
1485

1486
function deserialize_string(s::AbstractSerializer, len::Int)
203,580✔
1487
    out = ccall(:jl_alloc_string, Ref{String}, (Csize_t,), len)
203,582✔
1488
    unsafe_read(s.io, pointer(out), len)
203,582✔
1489
    return out
203,582✔
1490
end
1491

1492
# default DataType deserializer
1493
function deserialize(s::AbstractSerializer, t::DataType)
62,177✔
1494
    nf = length(t.types)
62,177✔
1495
    if isprimitivetype(t)
62,177✔
1496
        return read(s.io, t)
12✔
1497
    elseif ismutabletype(t)
62,165✔
1498
        x = ccall(:jl_new_struct_uninit, Any, (Any,), t)
2,864✔
1499
        deserialize_cycle(s, x)
2,864✔
1500
        for i in 1:nf
5,726✔
1501
            tag = Int32(read(s.io, UInt8)::UInt8)
9,041✔
1502
            if tag != UNDEFREF_TAG
9,041✔
1503
                ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), x, i-1, handle_deserialize(s, tag))
8,588✔
1504
            end
1505
        end
15,220✔
1506
        return x
2,864✔
1507
    elseif nf == 0
59,301✔
1508
        return ccall(:jl_new_struct_uninit, Any, (Any,), t)
31,364✔
1509
    else
1510
        na = nf
27,937✔
1511
        vflds = Vector{Any}(undef, nf)
27,937✔
1512
        for i in 1:nf
55,874✔
1513
            tag = Int32(read(s.io, UInt8)::UInt8)
59,816✔
1514
            if tag != UNDEFREF_TAG
59,816✔
1515
                f = handle_deserialize(s, tag)
59,815✔
1516
                na >= i && (vflds[i] = f)
59,813✔
1517
            else
1518
                na >= i && (na = i - 1) # rest of tail must be undefined values
1✔
1519
            end
1520
        end
91,693✔
1521
        return ccall(:jl_new_structv, Any, (Any, Ptr{Any}, UInt32), t, vflds, na)
27,935✔
1522
    end
1523
end
1524

1525
function deserialize_dict(s::AbstractSerializer, T::Type{<:AbstractDict})
5✔
1526
    n = read(s.io, Int32)
5✔
1527
    t = T(); sizehint!(t, n)
11✔
1528
    deserialize_cycle(s, t)
5✔
1529
    for i = 1:n
9✔
1530
        k = deserialize(s)
161✔
1531
        v = deserialize(s)
161✔
1532
        t[k] = v
161✔
1533
    end
318✔
1534
    return t
5✔
1535
end
1536

1537
function deserialize(s::AbstractSerializer, T::Type{Dict{K,V}}) where {K,V}
3✔
1538
    return deserialize_dict(s, T)
3✔
1539
end
1540

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

1543
function deserialize(s::AbstractSerializer, t::Type{Regex})
1✔
1544
    pattern = deserialize(s)
1✔
1545
    compile_options = deserialize(s)
1✔
1546
    match_options = deserialize(s)
1✔
1547
    return Regex(pattern, compile_options, match_options)
1✔
1548
end
1549

1550
## StackTraces
1551

1552
# provide a custom serializer that skips attempting to serialize the `outer_linfo`
1553
# which is likely to contain complex references, types, and module references
1554
# that may not exist on the receiver end
1555
function serialize(s::AbstractSerializer, frame::Base.StackTraces.StackFrame)
739✔
1556
    serialize_type(s, typeof(frame))
739✔
1557
    serialize(s, frame.func)
739✔
1558
    serialize(s, frame.file)
739✔
1559
    write(s.io, frame.line)
739✔
1560
    write(s.io, frame.from_c)
739✔
1561
    write(s.io, frame.inlined)
739✔
1562
    write(s.io, frame.pointer)
739✔
1563
    nothing
739✔
1564
end
1565

1566
function deserialize(s::AbstractSerializer, ::Type{Base.StackTraces.StackFrame})
739✔
1567
    func = deserialize(s)
739✔
1568
    file = deserialize(s)
739✔
1569
    line = read(s.io, Int)
739✔
1570
    from_c = read(s.io, Bool)
739✔
1571
    inlined = read(s.io, Bool)
739✔
1572
    pointer = read(s.io, UInt64)
739✔
1573
    return Base.StackTraces.StackFrame(func, file, line, nothing, from_c, inlined, pointer)
739✔
1574
end
1575

1576
function serialize(s::AbstractSerializer, lock::Base.AbstractLock)
18✔
1577
    # assert_havelock(lock)
1578
    serialize_cycle_header(s, lock)
35✔
1579
    nothing
18✔
1580
end
1581

1582
function deserialize(s::AbstractSerializer, ::Type{T}) where T<:Base.AbstractLock
17✔
1583
    lock = T()
17✔
1584
    deserialize_cycle(s, lock)
17✔
1585
    return lock
17✔
1586
end
1587

1588
function serialize(s::AbstractSerializer, cond::Base.GenericCondition)
2✔
1589
    serialize_cycle_header(s, cond) && return
4✔
1590
    serialize(s, cond.lock)
3✔
1591
    nothing
2✔
1592
end
1593

1594
function deserialize(s::AbstractSerializer, ::Type{T}) where T<:Base.GenericCondition
2✔
1595
    lock = deserialize(s)
2✔
1596
    cond = T(lock)
2✔
1597
    deserialize_cycle(s, cond)
2✔
1598
    return cond
2✔
1599
end
1600

1601
serialize(s::AbstractSerializer, l::LazyString) =
2✔
1602
    invoke(serialize, Tuple{AbstractSerializer,Any}, s, Base._LazyString((), string(l)))
1603

1604
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