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

JuliaLang / julia / #37551

pending completion
#37551

push

local

web-flow
Improve error when indexing is interpreted as a typed comprehension (#49939)

* Improve errors for typed_hcat by adding a special error for indexing that gets resolved as a typed comprehension.

* Add a test for issue #49676

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

71890 of 83662 relevant lines covered (85.93%)

34589844.48 hits per line

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

92.17
/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)
198✔
27
end
28

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

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

88
function sertag(@nospecialize(v))
418,701✔
89
    # NOTE: we use jl_value_ptr directly since we know at least one of the arguments
90
    # in the comparison below is a singleton.
91
    ptr = ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), v)
419,665✔
92
    ptags = convert(Ptr{Ptr{Cvoid}}, pointer(TAGS))
419,665✔
93
    # note: constant ints & reserved slots never returned here
94
    @inbounds for i in 1:(NTAGS-(n_reserved_slots+2*n_int_literals))
419,665✔
95
        ptr == unsafe_load(ptags,i) && return i%Int32
54,078,842✔
96
    end
107,553,738✔
97
    return Int32(-1)
235,384✔
98
end
99
desertag(i::Int32) = @inbounds(TAGS[i])
357,547✔
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,835,440✔
146

147
function write_as_tag(s::IO, tag)
194,129✔
148
    tag < VALUE_TAGS && write(s, UInt8(0))
194,368✔
149
    write(s, UInt8(tag))
217,590✔
150
    nothing
194,218✔
151
end
152

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

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

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

187
serialize(s::AbstractSerializer, x::Bool) = x ? writetag(s.io, TRUE_TAG) :
15,865✔
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)
43,824✔
193

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

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

216
function serialize(s::AbstractSerializer, x::Symbol)
133,952✔
217
    tag = sertag(x)
21,379,887✔
218
    if tag > 0
133,952✔
219
        return write_as_tag(s.io, tag)
46,193✔
220
    end
221
    pname = unsafe_convert(Ptr{UInt8}, x)
87,759✔
222
    len = Int(ccall(:strlen, Csize_t, (Cstring,), pname))
87,759✔
223
    if len > 7
87,759✔
224
        serialize_cycle(s, x) && return
47,570✔
225
    end
226
    if len <= NTAGS
82,002✔
227
        writetag(s.io, SYMBOL_TAG)
81,995✔
228
        write(s.io, UInt8(len))
82,262✔
229
    else
230
        writetag(s.io, LONGSYMBOL_TAG)
7✔
231
        write(s.io, Int32(len))
7✔
232
    end
233
    unsafe_write(s.io, pname, len)
82,002✔
234
    nothing
82,002✔
235
end
236

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

258
function serialize(s::AbstractSerializer, a::Array)
9,272✔
259
    serialize_cycle(s, a) && return
9,272✔
260
    elty = eltype(a)
9,269✔
261
    writetag(s.io, ARRAY_TAG)
9,270✔
262
    if elty !== UInt8
9,270✔
263
        serialize(s, elty)
8,452✔
264
    end
265
    if ndims(a) != 1
9,269✔
266
        serialize(s, size(a))
64✔
267
    else
268
        serialize(s, length(a))
9,206✔
269
    end
270
    if isbitstype(elty)
9,269✔
271
        serialize_array_data(s.io, a)
3,027✔
272
    else
273
        sizehint!(s.table, div(length(a),4))  # prepare for lots of pointers
6,267✔
274
        @inbounds for i in eachindex(a)
8,969✔
275
            if isassigned(a, i)
253,448✔
276
                serialize(s, a[i])
254,473✔
277
            else
278
                writetag(s.io, UNDEFREF_TAG)
2✔
279
            end
280
        end
253,448✔
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,082✔
292
    len = sizeof(ss)
205,082✔
293
    if len > 7
205,082✔
294
        serialize_cycle(s, ss) && return
203,334✔
295
        writetag(s.io, SHARED_REF_TAG)
201,933✔
296
    end
297
    if len <= NTAGS
203,681✔
298
        writetag(s.io, STRING_TAG)
203,623✔
299
        write(s.io, UInt8(len))
203,645✔
300
    else
301
        writetag(s.io, LONGSTRING_TAG)
58✔
302
        write(s.io, Int64(len))
58✔
303
    end
304
    write(s.io, ss)
203,681✔
305
    nothing
203,681✔
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,998✔
327
    serialize_cycle(s, ex) && return
3,998✔
328
    l = length(ex.args)
3,998✔
329
    if l <= NTAGS
3,998✔
330
        writetag(s.io, EXPR_TAG)
3,997✔
331
        write(s.io, UInt8(l))
4,317✔
332
    else
333
        writetag(s.io, LONGEXPR_TAG)
1✔
334
        write(s.io, Int32(l))
1✔
335
    end
336
    serialize(s, ex.head)
3,998✔
337
    for a in ex.args
4,002✔
338
        serialize(s, a)
9,366✔
339
    end
9,366✔
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)
192✔
346
        serialize(s, v)
192✔
347
    end
192✔
348
end
349

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

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

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

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

485
        v = getglobal(g.mod, g.name)
571✔
486
        unw = unwrap_unionall(v)
571✔
487
        if isa(unw,DataType) && v === unw.name.wrapper && should_send_whole_type(s, unw)
599✔
488
            # handle references to types in Main by sending the whole type.
489
            # needed to be able to send nested functions (#15451).
490
            writetag(s.io, FULL_GLOBALREF_TAG)
13✔
491
            serialize(s, v)
13✔
492
            return
13✔
493
        end
494
    end
495
    writetag(s.io, GLOBALREF_TAG)
1,770✔
496
    serialize(s, g.mod)
1,770✔
497
    serialize(s, g.name)
1,770✔
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)
407✔
508
    serialize(s, t.name)
407✔
509
    serialize(s, t.names)
407✔
510
    primary = unwrap_unionall(t.wrapper)
407✔
511
    serialize(s, primary.super)
407✔
512
    serialize(s, primary.parameters)
407✔
513
    serialize(s, primary.types)
407✔
514
    serialize(s, isdefined(primary, :instance))
472✔
515
    serialize(s, t.flags & 0x1 == 0x1) # .abstract
814✔
516
    serialize(s, t.flags & 0x2 == 0x2) # .mutable
814✔
517
    serialize(s, Int32(length(primary.types) - t.n_uninitialized))
407✔
518
    serialize(s, t.max_methods)
407✔
519
    if isdefined(t, :mt) && t.mt !== Symbol.name.mt
407✔
520
        serialize(s, t.mt.name)
406✔
521
        serialize(s, collect(Base.MethodList(t.mt)))
812✔
522
        serialize(s, t.mt.max_args)
406✔
523
        kws = collect(methods(Core.kwcall, (Any, t.wrapper, Vararg)))
407✔
524
        if isempty(kws)
406✔
525
            writetag(s.io, UNDEFREF_TAG)
405✔
526
        else
527
            serialize(s, kws)
407✔
528
        end
529
    else
530
        writetag(s.io, UNDEFREF_TAG)
1✔
531
    end
532
    nothing
407✔
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)
82,421✔
537
    tn = t.name
82,864✔
538
    if isdefined(tn, :mt)
82,864✔
539
        # TODO improve somehow
540
        # send whole type for anonymous functions in Main
541
        name = tn.mt.name
82,457✔
542
        mod = tn.module
82,457✔
543
        isanonfunction = mod === Main && # only Main
82,861✔
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
164,769✔
551
    end
552
    return false
407✔
553
end
554

555
function serialize_type_data(s, @nospecialize(t::DataType))
82,835✔
556
    whole = should_send_whole_type(s, t)
165,119✔
557
    iswrapper = (t === unwrap_unionall(t.name.wrapper))
82,835✔
558
    if whole && iswrapper
82,835✔
559
        writetag(s.io, WRAPPER_DATATYPE_TAG)
5,071✔
560
        serialize(s, t.name)
5,071✔
561
        return
5,071✔
562
    end
563
    serialize_cycle(s, t) && return
77,764✔
564
    if whole
56,524✔
565
        writetag(s.io, FULL_DATATYPE_TAG)
252✔
566
        serialize(s, t.name)
252✔
567
    else
568
        writetag(s.io, DATATYPE_TAG)
56,272✔
569
        serialize(s, nameof(t))
56,272✔
570
        serialize(s, parentmodule(t))
56,272✔
571
    end
572
    if !isempty(t.parameters)
56,524✔
573
        if iswrapper
39,237✔
574
            write(s.io, Int32(0))
4✔
575
        else
576
            write(s.io, Int32(length(t.parameters)))
39,233✔
577
            for p in t.parameters
78,466✔
578
                serialize(s, p)
109,352✔
579
            end
109,352✔
580
        end
581
    end
582
    nothing
56,524✔
583
end
584

585
function serialize(s::AbstractSerializer, t::DataType)
85,999✔
586
    tag = sertag(t)
6,718,939✔
587
    tag > 0 && return write_as_tag(s.io, tag)
85,999✔
588
    if t === Tuple
23,432✔
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)
23,432✔
596
end
597

598
function serialize_type(s::AbstractSerializer, @nospecialize(t::DataType), ref::Bool = false)
67,219✔
599
    tag = sertag(t)
10,088,513✔
600
    tag > 0 && return writetag(s.io, tag)
66,039✔
601
    writetag(s.io, ref ? REF_OBJECT_TAG : OBJECT_TAG)
59,401✔
602
    serialize_type_data(s, t)
59,401✔
603
end
604

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

615
function serialize(s::AbstractSerializer, n::Int64)
45,624✔
616
    if 0 <= n <= (n_int_literals-1)
45,624✔
617
        write(s.io, UInt8(ZERO64_TAG+n))
37,560✔
618
    elseif typemin(Int32) <= n <= typemax(Int32)
8,645✔
619
        writetag(s.io, SHORTINT64_TAG)
8,509✔
620
        write(s.io, Int32(n))
8,509✔
621
    else
622
        writetag(s.io, INT64_TAG)
136✔
623
        write(s.io, n)
136✔
624
    end
625
    nothing
45,624✔
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)
135,876✔
633
end
634

635
serialize(s::AbstractSerializer, ::Type{Bottom}) = write_as_tag(s.io, BOTTOM_TAG)
16,582✔
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)
182✔
641
        t = t.body
111✔
642
        n += 1
111✔
643
    end
111✔
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)
133,644✔
656

657
function serialize_any(s::AbstractSerializer, @nospecialize(x))
133,666✔
658
    tag = sertag(x)
16,127,644✔
659
    if tag > 0
133,666✔
660
        return write_as_tag(s.io, tag)
68,874✔
661
    end
662
    t = typeof(x)::DataType
64,792✔
663
    if isprimitivetype(t)
64,792✔
664
        serialize_type(s, t)
8✔
665
        write(s.io, x)
8✔
666
    else
667
        if ismutable(x)
64,784✔
668
            serialize_cycle(s, x) && return
1,627✔
669
            serialize_type(s, t, true)
1,525✔
670
        else
671
            serialize_type(s, t, false)
63,157✔
672
        end
673
        nf = nfields(x)
64,682✔
674
        for i in 1:nf
95,840✔
675
            if isdefined(x, i)
76,071✔
676
                serialize(s, getfield(x, i))
76,070✔
677
            else
678
                writetag(s.io, UNDEFREF_TAG)
1✔
679
            end
680
        end
76,071✔
681
    end
682
    nothing
64,690✔
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)
98✔
701
    io = s.io
98✔
702
    writetag(io, HEADER_TAG)
98✔
703
    write(io, "JL")  # magic bytes
98✔
704
    write(io, UInt8(ser_version))
194✔
705
    endianness = (ENDIAN_BOM == 0x04030201 ? 0 :
96✔
706
                  ENDIAN_BOM == 0x01020304 ? 1 :
707
                  error("unsupported endianness in serializer"))
708
    machine = (sizeof(Int) == 4 ? 0 :
96✔
709
               sizeof(Int) == 8 ? 1 :
710
               error("unsupported word size in serializer"))
711
    write(io, UInt8(endianness) | (UInt8(machine) << 2))
194✔
712
    write(io, [0x00,0x00,0x00]) # 3 reserved bytes
294✔
713
    nothing
98✔
714
end
715

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

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

834
function gettable(s::AbstractSerializer, id::Int)
29,774✔
835
    get(s.table, id) do
30,475✔
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,138,685✔
851
    if b == 0
1,138,685✔
852
        return desertag(Int32(read(s.io, UInt8)::UInt8))
25,678✔
853
    end
854
    if b >= VALUE_TAGS
1,113,007✔
855
        return desertag(b)
321,295✔
856
    elseif b == TUPLE_TAG
791,712✔
857
        return deserialize_tuple(s, Int(read(s.io, UInt8)::UInt8))
10,671✔
858
    elseif b == SHORTBACKREF_TAG
781,041✔
859
        id = read(s.io, UInt16)::UInt16
30,474✔
860
        return gettable(s, Int(id))
30,474✔
861
    elseif b == BACKREF_TAG
750,567✔
862
        id = read(s.io, Int32)::Int32
1✔
863
        return gettable(s, Int(id))
1✔
864
    elseif b == ARRAY_TAG
750,566✔
865
        return deserialize_array(s)
9,294✔
866
    elseif b == DATATYPE_TAG
741,272✔
867
        return deserialize_datatype(s, false)
56,295✔
868
    elseif b == FULL_DATATYPE_TAG
684,977✔
869
        return deserialize_datatype(s, true)
264✔
870
    elseif b == WRAPPER_DATATYPE_TAG
684,713✔
871
        tname = deserialize(s)::Core.TypeName
5,074✔
872
        return unwrap_unionall(tname.wrapper)
5,070✔
873
    elseif b == OBJECT_TAG
679,639✔
874
        t = deserialize(s)
58,414✔
875
        if t === Missing
58,410✔
876
            return missing
×
877
        end
878
        return deserialize(s, t)
58,410✔
879
    elseif b == REF_OBJECT_TAG
621,225✔
880
        slot = s.counter; s.counter += 1
2,070✔
881
        push!(s.pending_refs, slot)
1,035✔
882
        t = deserialize(s)
1,035✔
883
        return deserialize(s, t)
1,034✔
884
    elseif b == SHARED_REF_TAG
620,190✔
885
        slot = s.counter; s.counter += 1
403,884✔
886
        obj = deserialize(s)
201,942✔
887
        s.table[slot] = obj
201,942✔
888
        return obj
201,942✔
889
    elseif b == SYMBOL_TAG
418,248✔
890
        return deserialize_symbol(s, Int(read(s.io, UInt8)::UInt8))
82,035✔
891
    elseif b == SHORTINT64_TAG
336,213✔
892
        return Int64(read(s.io, Int32)::Int32)
8,568✔
893
    elseif b == EXPR_TAG
327,645✔
894
        return deserialize_expr(s, Int(read(s.io, UInt8)::UInt8))
4,003✔
895
    elseif b == MODULE_TAG
323,642✔
896
        return deserialize_module(s)
59,584✔
897
    elseif b == STRING_TAG
264,058✔
898
        return deserialize_string(s, Int(read(s.io, UInt8)::UInt8))
203,624✔
899
    elseif b == LONGSTRING_TAG
60,434✔
900
        return deserialize_string(s, Int(read(s.io, Int64)::Int64))
80✔
901
    elseif b == SIMPLEVECTOR_TAG
60,354✔
902
        return deserialize_svec(s)
1,228✔
903
    elseif b == GLOBALREF_TAG
59,126✔
904
        return GlobalRef(deserialize(s)::Module, deserialize(s)::Symbol)
1,775✔
905
    elseif b == FULL_GLOBALREF_TAG
57,351✔
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
57,338✔
910
        return deserialize_tuple(s, Int(read(s.io, Int32)::Int32))
1✔
911
    elseif b == LONGEXPR_TAG
57,337✔
912
        return deserialize_expr(s, Int(read(s.io, Int32)::Int32))
1✔
913
    elseif b == LONGBACKREF_TAG
57,336✔
914
        id = read(s.io, Int64)::Int64
×
915
        return gettable(s, Int(id))
×
916
    elseif b == LONGSYMBOL_TAG
57,336✔
917
        return deserialize_symbol(s, Int(read(s.io, Int32)::Int32))
7✔
918
    elseif b == HEADER_TAG
57,329✔
919
        readheader(s)
101✔
920
        return deserialize(s)
97✔
921
    elseif b == INT8_TAG
57,228✔
922
        return read(s.io, Int8)
20✔
923
    elseif b == INT8_TAG+1
57,208✔
924
        return read(s.io, UInt8)
2,721✔
925
    elseif b == INT8_TAG+2
54,487✔
926
        return read(s.io, Int16)
12✔
927
    elseif b == INT8_TAG+3
54,475✔
928
        return read(s.io, UInt16)
419✔
929
    elseif b == INT32_TAG
54,056✔
930
        return read(s.io, Int32)
1,268✔
931
    elseif b == INT8_TAG+5
52,788✔
932
        return read(s.io, UInt32)
15✔
933
    elseif b == INT64_TAG
52,773✔
934
        return read(s.io, Int64)
140✔
935
    elseif b == INT8_TAG+7
52,633✔
936
        return read(s.io, UInt64)
1,214✔
937
    elseif b == INT8_TAG+8
51,419✔
938
        return read(s.io, Int128)
11,074✔
939
    elseif b == INT8_TAG+9
40,345✔
940
        return read(s.io, UInt128)
18,111✔
941
    elseif b == INT8_TAG+10
22,234✔
942
        return read(s.io, Float16)
4✔
943
    elseif b == INT8_TAG+11
22,230✔
944
        return read(s.io, Float32)
×
945
    elseif b == INT8_TAG+12
22,230✔
946
        return read(s.io, Float64)
517✔
947
    elseif b == INT8_TAG+13
21,713✔
948
        return read(s.io, Char)
11,137✔
949
    elseif b == IDDICT_TAG
10,576✔
950
        slot = s.counter; s.counter += 1
4✔
951
        push!(s.pending_refs, slot)
2✔
952
        t = deserialize(s)
2✔
953
        return deserialize_dict(s, t)
2✔
954
    end
955
    t = desertag(b)::DataType
10,574✔
956
    if ismutabletype(t) && length(t.types) > 0  # manual specialization of fieldcount
10,574✔
957
        slot = s.counter; s.counter += 1
8,992✔
958
        push!(s.pending_refs, slot)
4,496✔
959
    end
960
    return deserialize(s, t)
10,574✔
961
end
962

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

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

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

980
function deserialize_module(s::AbstractSerializer)
59,584✔
981
    mkey = deserialize(s)
59,584✔
982
    if isa(mkey, Tuple)
59,584✔
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)
59,584✔
993
        pkg = (mkey === nothing) ? Base.PkgId(name) : Base.PkgId(Base.UUID(mkey), name)
77,464✔
994
        m = Base.root_module(pkg)
59,584✔
995
        mname = deserialize(s)
59,584✔
996
        while mname !== ()
59,814✔
997
            m = getglobal(m, mname)::Module
232✔
998
            mname = deserialize(s)
230✔
999
        end
230✔
1000
    end
1001
    return m
59,582✔
1002
end
1003

1004
function deserialize(s::AbstractSerializer, ::Type{Method})
409✔
1005
    lnumber = read(s.io, UInt64)
409✔
1006
    meth = lookup_object_number(s, lnumber)
410✔
1007
    if meth !== nothing
409✔
1008
        meth = meth::Method
1✔
1009
        makenew = false
1✔
1010
    else
1011
        meth = ccall(:jl_new_method_uninit, Ref{Method}, (Any,), Main)
408✔
1012
        makenew = true
408✔
1013
    end
1014
    deserialize_cycle(s, meth)
409✔
1015
    mod = deserialize(s)::Module
409✔
1016
    name = deserialize(s)::Symbol
409✔
1017
    file = deserialize(s)::Symbol
409✔
1018
    line = deserialize(s)::Int32
409✔
1019
    sig = deserialize(s)::Type
409✔
1020
    syms = deserialize(s)
409✔
1021
    if syms isa SimpleVector
409✔
1022
        # < v1.2
1023
        _ambig = deserialize(s)
1✔
1024
    else
1025
        slot_syms = syms::String
408✔
1026
    end
1027
    nargs = deserialize(s)::Int32
409✔
1028
    isva = deserialize(s)::Bool
409✔
1029
    is_for_opaque_closure = false
409✔
1030
    nospecializeinfer = false
409✔
1031
    constprop = purity = 0x00
409✔
1032
    template_or_is_opaque = deserialize(s)
409✔
1033
    if isa(template_or_is_opaque, Bool)
409✔
1034
        is_for_opaque_closure = template_or_is_opaque
408✔
1035
        if format_version(s) >= 24
408✔
1036
            nospecializeinfer = deserialize(s)::Bool
408✔
1037
        end
1038
        if format_version(s) >= 14
408✔
1039
            constprop = deserialize(s)::UInt8
408✔
1040
        end
1041
        if format_version(s) >= 17
408✔
1042
            purity = deserialize(s)::UInt8
408✔
1043
        end
1044
        template = deserialize(s)
408✔
1045
    else
1046
        template = template_or_is_opaque
1✔
1047
    end
1048
    generator = deserialize(s)
408✔
1049
    recursion_relation = nothing
408✔
1050
    if format_version(s) >= 15
408✔
1051
        recursion_relation = deserialize(s)
407✔
1052
    end
1053
    if makenew
408✔
1054
        meth.module = mod
407✔
1055
        meth.name = name
407✔
1056
        meth.file = file
407✔
1057
        meth.line = line
407✔
1058
        meth.sig = sig
407✔
1059
        meth.nargs = nargs
407✔
1060
        meth.isva = isva
407✔
1061
        meth.is_for_opaque_closure = is_for_opaque_closure
407✔
1062
        meth.nospecializeinfer = nospecializeinfer
407✔
1063
        meth.constprop = constprop
407✔
1064
        meth.purity = purity
407✔
1065
        if template !== nothing
407✔
1066
            # TODO: compress template
1067
            meth.source = template::CodeInfo
407✔
1068
            if !@isdefined(slot_syms)
407✔
1069
                slot_syms = ccall(:jl_compress_argnames, Ref{String}, (Any,), meth.source.slotnames)
1✔
1070
            end
1071
        end
1072
        meth.slot_syms = slot_syms
407✔
1073
        if generator !== nothing
407✔
1074
            meth.generator = generator
×
1075
        end
1076
        if recursion_relation !== nothing
407✔
1077
            meth.recursion_relation = recursion_relation
×
1078
        end
1079
        if !is_for_opaque_closure
407✔
1080
            mt = ccall(:jl_method_table_for, Any, (Any,), sig)
407✔
1081
            if mt !== nothing && nothing === ccall(:jl_methtable_lookup, Any, (Any, Any, UInt), mt, sig, typemax(UInt))
407✔
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)
407✔
1086
    end
1087
    return meth
408✔
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})
885✔
1110
    mod = deserialize(s)
885✔
1111
    if mod isa Module
885✔
1112
        method = deserialize(s)
885✔
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}))
885✔
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})
409✔
1131
    ci = ccall(:jl_new_code_info_uninit, Ref{CodeInfo}, ())
409✔
1132
    deserialize_cycle(s, ci)
409✔
1133
    code = deserialize(s)::Vector{Any}
409✔
1134
    ci.code = code
408✔
1135
    # allow older-style IR with return and gotoifnot Exprs
1136
    for i in 1:length(code)
816✔
1137
        stmt = code[i]
2,682✔
1138
        if isa(stmt, Expr)
2,682✔
1139
            ex = stmt::Expr
1,656✔
1140
            if ex.head === :return
1,656✔
1141
                code[i] = ReturnNode(isempty(ex.args) ? nothing : ex.args[1])
2✔
1142
            elseif ex.head === :gotoifnot
1,655✔
1143
                code[i] = GotoIfNot(ex.args[1], ex.args[2])
×
1144
            end
1145
        end
1146
    end
4,956✔
1147
    ci.codelocs = deserialize(s)::Vector{Int32}
408✔
1148
    _x = deserialize(s)
408✔
1149
    if _x isa Array || _x isa Int
816✔
1150
        pre_12 = false
407✔
1151
        ci.ssavaluetypes = _x
407✔
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)
408✔
1160
    if length(ssaflags) ≠ length(code)
408✔
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 = UInt8[0x00 for _ in 1:length(code)]
3✔
1164
    end
1165
    ci.ssaflags = ssaflags
408✔
1166
    if pre_12
408✔
1167
        ci.slotflags = deserialize(s)
1✔
1168
    else
1169
        ci.method_for_inference_limit_heuristics = deserialize(s)
407✔
1170
        ci.linetable = deserialize(s)
407✔
1171
    end
1172
    ci.slotnames = deserialize(s)
408✔
1173
    if !pre_12
408✔
1174
        ci.slotflags = deserialize(s)
407✔
1175
        ci.slottypes = deserialize(s)
407✔
1176
        ci.rettype = deserialize(s)
407✔
1177
        ci.parent = deserialize(s)
407✔
1178
        world_or_edges = deserialize(s)
407✔
1179
        pre_13 = isa(world_or_edges, Integer)
407✔
1180
        if pre_13
407✔
1181
            ci.min_world = world_or_edges
×
1182
        else
1183
            ci.edges = world_or_edges
407✔
1184
            ci.min_world = reinterpret(UInt, deserialize(s))
407✔
1185
            ci.max_world = reinterpret(UInt, deserialize(s))
407✔
1186
        end
1187
    end
1188
    ci.inferred = deserialize(s)
408✔
1189
    if format_version(s) < 22
408✔
1190
        inlining_cost = deserialize(s)
1✔
1191
        if isa(inlining_cost, Bool)
1✔
1192
            Core.Compiler.set_inlineable!(ci, inlining_cost)
1✔
1193
        else
1194
            ci.inlining_cost = inlining_cost
×
1195
        end
1196
    end
1197
    ci.propagate_inbounds = deserialize(s)
408✔
1198
    if format_version(s) < 23
408✔
1199
        deserialize(s) # `pure` field has been removed
1✔
1200
    end
1201
    if format_version(s) >= 20
408✔
1202
        ci.has_fcall = deserialize(s)
407✔
1203
    end
1204
    if format_version(s) >= 24
408✔
1205
        ci.nospecializeinfer = deserialize(s)::Bool
407✔
1206
    end
1207
    if format_version(s) >= 21
408✔
1208
        ci.inlining = deserialize(s)::UInt8
407✔
1209
    end
1210
    if format_version(s) >= 14
408✔
1211
        ci.constprop = deserialize(s)::UInt8
407✔
1212
    end
1213
    if format_version(s) >= 17
408✔
1214
        ci.purity = deserialize(s)::UInt8
407✔
1215
    end
1216
    if format_version(s) >= 22
408✔
1217
        ci.inlining_cost = deserialize(s)::UInt16
407✔
1218
    end
1219
    return ci
408✔
1220
end
1221

1222
if Int === Int64
1223
const OtherInt = Int32
1224
else
1225
const OtherInt = Int64
1226
end
1227

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

1277
function deserialize_fillarray!(A::Array{T}, s::AbstractSerializer) where {T}
6,281✔
1278
    for i = eachindex(A)
9,023✔
1279
        tag = Int32(read(s.io, UInt8)::UInt8)
253,471✔
1280
        if tag != UNDEFREF_TAG
253,471✔
1281
            @inbounds A[i] = handle_deserialize(s, tag)
253,469✔
1282
        end
1283
    end
504,198✔
1284
    return A
6,279✔
1285
end
1286

1287
function deserialize_expr(s::AbstractSerializer, len)
4,004✔
1288
    e = Expr(:temp)
4,004✔
1289
    resolve_ref_immediately(s, e)
4,004✔
1290
    e.head = deserialize(s)::Symbol
4,004✔
1291
    e.args = Any[ deserialize(s) for i = 1:len ]
9,386✔
1292
    e
4,004✔
1293
end
1294

1295
module __deserialized_types__ end
1296

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

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

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

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

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

1391
function deserialize_datatype(s::AbstractSerializer, full::Bool)
56,559✔
1392
    slot = s.counter; s.counter += 1
113,118✔
1393
    if full
56,559✔
1394
        tname = deserialize(s)::Core.TypeName
264✔
1395
        ty = tname.wrapper
264✔
1396
    else
1397
        name = deserialize(s)::Symbol
56,295✔
1398
        mod = deserialize(s)::Module
56,295✔
1399
        ty = getglobal(mod, name)
56,295✔
1400
    end
1401
    if isa(ty,DataType) && isempty(ty.parameters)
56,555✔
1402
        t = ty
17,340✔
1403
    else
1404
        np = Int(read(s.io, Int32)::Int32)
39,215✔
1405
        if np == 0
39,215✔
1406
            t = unwrap_unionall(ty)
4✔
1407
        elseif ty === Tuple
39,211✔
1408
            # note np==0 has its own tag
1409
            if np == 1
1,702✔
1410
                t = Tuple{deserialize(s)}
1,081✔
1411
            elseif np == 2
621✔
1412
                t = Tuple{deserialize(s), deserialize(s)}
485✔
1413
            elseif np == 3
136✔
1414
                t = Tuple{deserialize(s), deserialize(s), deserialize(s)}
85✔
1415
            elseif np == 4
51✔
1416
                t = Tuple{deserialize(s), deserialize(s), deserialize(s), deserialize(s)}
29✔
1417
            else
1418
                t = Tuple{Any[ deserialize(s) for i=1:np ]...}
1,724✔
1419
            end
1420
        else
1421
            t = ty
37,507✔
1422
            for i = 1:np
75,018✔
1423
                t = t{deserialize(s)}
106,788✔
1424
            end
106,788✔
1425
        end
1426
    end
1427
    s.table[slot] = t
56,555✔
1428
    return t
56,555✔
1429
end
1430

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

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

1484
function deserialize_string(s::AbstractSerializer, len::Int)
203,703✔
1485
    out = ccall(:jl_alloc_string, Ref{String}, (Csize_t,), len)
203,704✔
1486
    unsafe_read(s.io, pointer(out), len)
203,704✔
1487
    return out
203,704✔
1488
end
1489

1490
# default DataType deserializer
1491
function deserialize(s::AbstractSerializer, t::DataType)
63,631✔
1492
    nf = length(t.types)
63,631✔
1493
    if isprimitivetype(t)
63,631✔
1494
        return read(s.io, t)
8✔
1495
    elseif ismutabletype(t)
63,623✔
1496
        x = ccall(:jl_new_struct_uninit, Any, (Any,), t)
1,270✔
1497
        deserialize_cycle(s, x)
1,270✔
1498
        for i in 1:nf
2,538✔
1499
            tag = Int32(read(s.io, UInt8)::UInt8)
4,259✔
1500
            if tag != UNDEFREF_TAG
4,259✔
1501
                ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), x, i-1, handle_deserialize(s, tag))
3,806✔
1502
            end
1503
        end
7,250✔
1504
        return x
1,270✔
1505
    elseif nf == 0
62,353✔
1506
        return ccall(:jl_new_struct_uninit, Any, (Any,), t)
33,511✔
1507
    else
1508
        na = nf
28,842✔
1509
        vflds = Vector{Any}(undef, nf)
28,842✔
1510
        for i in 1:nf
57,684✔
1511
            tag = Int32(read(s.io, UInt8)::UInt8)
59,990✔
1512
            if tag != UNDEFREF_TAG
59,990✔
1513
                f = handle_deserialize(s, tag)
59,989✔
1514
                na >= i && (vflds[i] = f)
59,987✔
1515
            else
1516
                na >= i && (na = i - 1) # rest of tail must be undefined values
1✔
1517
            end
1518
        end
91,136✔
1519
        return ccall(:jl_new_structv, Any, (Any, Ptr{Any}, UInt32), t, vflds, na)
28,840✔
1520
    end
1521
end
1522

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

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

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

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

1548
## StackTraces
1549

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

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

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

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

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

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

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

1602
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