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

JuliaLang / julia / #38085

30 May 2025 07:47AM UTC coverage: 25.777% (+0.004%) from 25.773%
#38085

push

local

web-flow
test: Fix accidentally left over make dependency (#58571)

12849 of 49847 relevant lines covered (25.78%)

711119.92 hits per line

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

35.04
/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: Bottom, unsafe_convert
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)
2✔
27
end
28

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

85
format_version(::AbstractSerializer) = ser_version
×
86
format_version(s::Serializer) = s.version
×
87

88
function sertag(@nospecialize(v))
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)
1,447✔
92
    ptags = convert(Ptr{Ptr{Cvoid}}, pointer(TAGS))
1,447✔
93
    # note: constant ints & reserved slots never returned here
94
    @inbounds for i in 1:(NTAGS-(n_reserved_slots+2*n_int_literals))
1,447✔
95
        ptr == unsafe_load(ptags,i) && return i%Int32
230,739✔
96
    end
459,927✔
97
    return Int32(-1)
1,343✔
98
end
99
desertag(i::Int32) = @inbounds(TAGS[i])
204✔
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)
9,594✔
146

147
function write_as_tag(s::IO, tag)
148
    tag < VALUE_TAGS && write(s, UInt8(0))
114✔
149
    write(s, UInt8(tag))
114✔
150
    nothing
114✔
151
end
152

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

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

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

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

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

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

194
function serialize(s::AbstractSerializer, t::Tuple)
8✔
195
    l = length(t)
8✔
196
    if l <= NTAGS
8✔
197
        writetag(s.io, TUPLE_TAG)
8✔
198
        write(s.io, UInt8(l))
8✔
199
    else
200
        writetag(s.io, LONGTUPLE_TAG)
×
201
        write(s.io, Int32(l))
×
202
    end
203
    for x in t
8✔
204
        serialize(s, x)
16✔
205
    end
12✔
206
end
207

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

216
function serialize(s::AbstractSerializer, x::Symbol)
74✔
217
    tag = sertag(x)
12,014✔
218
    if tag > 0
74✔
219
        return write_as_tag(s.io, tag)
30✔
220
    end
221
    pname = unsafe_convert(Ptr{UInt8}, x)
44✔
222
    len = Int(ccall(:strlen, Csize_t, (Cstring,), pname))
44✔
223
    if len > 7
44✔
224
        serialize_cycle(s, x) && return
25✔
225
    end
226
    if len <= NTAGS
44✔
227
        writetag(s.io, SYMBOL_TAG)
44✔
228
        write(s.io, UInt8(len))
44✔
229
    else
230
        writetag(s.io, LONGSYMBOL_TAG)
×
231
        write(s.io, Int32(len))
×
232
    end
233
    unsafe_write(s.io, pname, len)
44✔
234
    nothing
44✔
235
end
236

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

258
function serialize(s::AbstractSerializer, a::Array)
12✔
259
    serialize_cycle(s, a) && return
12✔
260
    elty = eltype(a)
12✔
261
    writetag(s.io, ARRAY_TAG)
12✔
262
    if elty !== UInt8
12✔
263
        serialize(s, elty)
12✔
264
    end
265
    if ndims(a) != 1
12✔
266
        serialize(s, size(a))
×
267
    else
268
        serialize(s, length(a))
12✔
269
    end
270
    if isbitstype(elty)
12✔
271
        serialize_array_data(s.io, a)
4✔
272
    else
273
        sizehint!(s.table, div(length(a),4))  # prepare for lots of pointers
9✔
274
        @inbounds for i in eachindex(a)
8✔
275
            if isassigned(a, i)
365✔
276
                serialize(s, a[i])
725✔
277
            else
278
                writetag(s.io, UNDEFREF_TAG)
×
279
            end
280
        end
365✔
281
    end
282
end
283

284
function serialize(s::AbstractSerializer, a::SubArray{T,N,A}) where {T,N,A<:Array}
×
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)
×
288
    serialize_any(s, b)
×
289
end
290

291
serialize(s::AbstractSerializer, m::GenericMemory) = error("GenericMemory{:atomic} currently cannot be serialized")
×
292
function serialize(s::AbstractSerializer, m::Memory)
×
293
    serialize_cycle_header(s, m) && return
×
294
    serialize(s, length(m))
×
295
    elty = eltype(m)
×
296
    if isbitstype(elty)
×
297
        serialize_array_data(s.io, m)
×
298
    else
299
        sizehint!(s.table, div(length(m),4))  # prepare for lots of pointers
×
300
        @inbounds for i in eachindex(m)
×
301
            if isassigned(m, i)
×
302
                serialize(s, m[i])
×
303
            else
304
                writetag(s.io, UNDEFREF_TAG)
×
305
            end
306
        end
×
307
    end
308
end
309

310
function serialize(s::AbstractSerializer, x::GenericMemoryRef)
×
311
    serialize_type(s, typeof(x))
×
312
    serialize(s, getfield(x, :mem))
×
313
    serialize(s, Base.memoryrefoffset(x))
×
314
end
315

316
function serialize(s::AbstractSerializer, ss::String)
5,813✔
317
    len = sizeof(ss)
5,813✔
318
    if len > 7
5,813✔
319
        serialize_cycle(s, ss) && return
2,795✔
320
        writetag(s.io, SHARED_REF_TAG)
718✔
321
    end
322
    if len <= NTAGS
3,736✔
323
        writetag(s.io, STRING_TAG)
3,734✔
324
        write(s.io, UInt8(len))
3,734✔
325
    else
326
        writetag(s.io, LONGSTRING_TAG)
2✔
327
        write(s.io, Int64(len))
2✔
328
    end
329
    write(s.io, ss)
3,736✔
330
    nothing
3,736✔
331
end
332

333
function serialize(s::AbstractSerializer, ss::SubString{String})
3✔
334
    # avoid saving a copy of the parent string, keeping the type of ss
335
    serialize_any(s, SubString(String(ss)))
3✔
336
end
337

338
# Don't serialize the pointers
339
function serialize(s::AbstractSerializer, r::Regex)
×
340
    serialize_type(s, typeof(r))
×
341
    serialize(s, r.pattern)
×
342
    serialize(s, r.compile_options)
×
343
    serialize(s, r.match_options)
×
344
end
345

346
function serialize(s::AbstractSerializer, n::BigInt)
×
347
    serialize_type(s, BigInt)
×
348
    serialize(s, string(n, base = 62))
×
349
end
350

351
function serialize(s::AbstractSerializer, ex::Expr)
×
352
    serialize_cycle(s, ex) && return
×
353
    l = length(ex.args)
×
354
    if l <= NTAGS
×
355
        writetag(s.io, EXPR_TAG)
×
356
        write(s.io, UInt8(l))
×
357
    else
358
        writetag(s.io, LONGEXPR_TAG)
×
359
        write(s.io, Int32(l))
×
360
    end
361
    serialize(s, ex.head)
×
362
    for a in ex.args
×
363
        serialize(s, a)
×
364
    end
×
365
end
366

367
function serialize_dict_data(s::AbstractSerializer, d::AbstractDict)
502✔
368
    write(s.io, Int32(length(d)))
502✔
369
    for (k,v) in d
1,004✔
370
        serialize(s, k)
3,515✔
371
        serialize(s, v)
3,515✔
372
    end
3,515✔
373
end
374

375
function serialize(s::AbstractSerializer, d::Dict)
718✔
376
    serialize_cycle_header(s, d) && return
1,580✔
377
    serialize_dict_data(s, d)
502✔
378
end
379

380
function serialize(s::AbstractSerializer, d::IdDict)
×
381
    serialize_cycle(s, d) && return
×
382
    writetag(s.io, IDDICT_TAG)
×
383
    serialize_type_data(s, typeof(d))
×
384
    serialize_dict_data(s, d)
×
385
end
386

387
function serialize_mod_names(s::AbstractSerializer, m::Module)
36✔
388
    p = parentmodule(m)
36✔
389
    if p === m || m === Base
58✔
390
        key = Base.root_module_key(m)
34✔
391
        uuid = key.uuid
34✔
392
        serialize(s, uuid === nothing ? nothing : uuid.value)
38✔
393
        serialize(s, Symbol(key.name))
34✔
394
    else
395
        serialize_mod_names(s, p)
2✔
396
        serialize(s, nameof(m))
2✔
397
    end
398
end
399

400
function serialize(s::AbstractSerializer, m::Module)
34✔
401
    writetag(s.io, MODULE_TAG)
34✔
402
    serialize_mod_names(s, m)
34✔
403
    writetag(s.io, EMPTYTUPLE_TAG)
34✔
404
end
405

406
# TODO: make this bidirectional, so objects can be sent back via the same key
407
const object_numbers = WeakKeyDict()
408
const obj_number_salt = Ref{UInt64}(0)
409
function object_number(s::AbstractSerializer, @nospecialize(l))
410
    global obj_number_salt, object_numbers
×
411
    if haskey(object_numbers, l)
×
412
        return object_numbers[l]
×
413
    end
414
    ln = obj_number_salt[]
×
415
    object_numbers[l] = ln
×
416
    obj_number_salt[] += 1
×
417
    return ln::UInt64
×
418
end
419

420
lookup_object_number(s::AbstractSerializer, n::UInt64) = nothing
×
421

422
remember_object(s::AbstractSerializer, @nospecialize(o), n::UInt64) = nothing
×
423

424
function lookup_object_number(s::Serializer, n::UInt64)
×
425
    return get(s.known_object_data, n, nothing)
×
426
end
427

428
function remember_object(s::Serializer, @nospecialize(o), n::UInt64)
×
429
    s.known_object_data[n] = o
×
430
    return nothing
×
431
end
432

433
function serialize(s::AbstractSerializer, meth::Method)
×
434
    serialize_cycle(s, meth) && return
×
435
    writetag(s.io, METHOD_TAG)
×
436
    write(s.io, object_number(s, meth))
×
437
    serialize(s, meth.module)
×
438
    serialize(s, meth.name)
×
439
    serialize(s, meth.file)
×
440
    serialize(s, meth.line)
×
441
    serialize(s, meth.sig)
×
442
    serialize(s, meth.slot_syms)
×
443
    serialize(s, meth.nargs)
×
444
    serialize(s, meth.isva)
×
445
    serialize(s, meth.is_for_opaque_closure)
×
446
    serialize(s, meth.nospecializeinfer)
×
447
    serialize(s, meth.constprop)
×
448
    serialize(s, meth.purity)
×
449
    if isdefined(meth, :source)
×
450
        serialize(s, Base._uncompressed_ast(meth))
×
451
    else
452
        serialize(s, nothing)
×
453
    end
454
    if isdefined(meth, :generator)
×
455
        serialize(s, meth.generator)
×
456
    else
457
        serialize(s, nothing)
×
458
    end
459
    if isdefined(meth, :recursion_relation)
×
460
        serialize(s, method.recursion_relation)
×
461
    else
462
        serialize(s, nothing)
×
463
    end
464
    if isdefined(meth, :external_mt)
×
465
        error("cannot serialize Method objects with external method tables")
×
466
    end
467
    nothing
×
468
end
469

470
function serialize(s::AbstractSerializer, mt::Core.MethodTable)
×
471
    serialize_type(s, typeof(mt))
×
472
    serialize(s, mt.name)
×
473
    serialize(s, mt.module)
×
474
    nothing
×
475
end
476

477
function serialize(s::AbstractSerializer, mc::Core.MethodCache)
×
478
    error("cannot serialize MethodCache objects")
×
479
end
480

481

482
function serialize(s::AbstractSerializer, linfo::Core.MethodInstance)
×
483
    serialize_cycle(s, linfo) && return
×
484
    writetag(s.io, METHODINSTANCE_TAG)
×
485
    serialize(s, nothing)  # for backwards compat
×
486
    serialize(s, linfo.sparam_vals)
×
487
    serialize(s, Any)  # for backwards compat
×
488
    serialize(s, linfo.specTypes)
×
489
    serialize(s, linfo.def)
×
490
    nothing
×
491
end
492

493
function serialize(s::AbstractSerializer, t::Task)
×
494
    serialize_cycle(s, t) && return
×
495
    if istaskstarted(t) && !istaskdone(t)
×
496
        error("cannot serialize a running Task")
×
497
    end
498
    writetag(s.io, TASK_TAG)
×
499
    serialize(s, t.code)
×
500
    serialize(s, t.storage)
×
501
    serialize(s, t.state)
×
502
    if t._isexception && (stk = Base.current_exceptions(t); !isempty(stk))
×
503
        # the exception stack field is hidden inside the task, so if there
504
        # is any information there make a CapturedException from it instead.
505
        # TODO: Handle full exception chain, not just the first one.
506
        serialize(s, CapturedException(stk[1].exception, stk[1].backtrace))
×
507
    else
508
        serialize(s, t.result)
×
509
    end
510
    serialize(s, t._isexception)
×
511
end
512

513
function serialize(s::AbstractSerializer, g::GlobalRef)
×
514
    if (g.mod === __deserialized_types__ ) ||
×
515
        (g.mod === Main && isdefined(g.mod, g.name) && isconst(g.mod, g.name))
516

517
        v = getglobal(g.mod, g.name)
×
518
        unw = unwrap_unionall(v)
×
519
        if isa(unw,DataType) && v === unw.name.wrapper && should_send_whole_type(s, unw)
×
520
            # handle references to types in Main by sending the whole type.
521
            # needed to be able to send nested functions (#15451).
522
            writetag(s.io, FULL_GLOBALREF_TAG)
×
523
            serialize(s, v)
×
524
            return
×
525
        end
526
    end
527
    writetag(s.io, GLOBALREF_TAG)
×
528
    serialize(s, g.mod)
×
529
    serialize(s, g.name)
×
530
end
531

532
function serialize(s::AbstractSerializer, t::Core.TypeName)
×
533
    serialize_cycle(s, t) && return
×
534
    writetag(s.io, TYPENAME_TAG)
×
535
    write(s.io, object_number(s, t))
×
536
    serialize_typename(s, t)
×
537
end
538

539
function serialize_typename(s::AbstractSerializer, t::Core.TypeName)
×
540
    serialize(s, t.name)
×
541
    serialize(s, t.names)
×
542
    primary = unwrap_unionall(t.wrapper)
×
543
    serialize(s, primary.super)
×
544
    serialize(s, primary.parameters)
×
545
    serialize(s, primary.types)
×
546
    serialize(s, Base.issingletontype(primary))
×
547
    serialize(s, t.flags & 0x1 == 0x1) # .abstract
×
548
    serialize(s, t.flags & 0x2 == 0x2) # .mutable
×
549
    serialize(s, Int32(length(primary.types) - t.n_uninitialized))
×
550
    serialize(s, t.max_methods)
×
551
    ms = Base.matches_to_methods(Base._methods_by_ftype(Tuple{t.wrapper, Vararg}, -1, Base.get_world_counter()), t, nothing).ms
×
552
    if t.singletonname !== t.name || !isempty(ms)
×
553
        serialize(s, t.singletonname)
×
554
        serialize(s, ms)
×
555
        serialize(s, t.max_args)
×
556
        kws = Base.matches_to_methods(Base._methods_by_ftype(Tuple{typeof(Core.kwcall), Any, t.wrapper, Vararg}, -1, Base.get_world_counter()), t, nothing).ms
×
557
        if isempty(kws)
×
558
            writetag(s.io, UNDEFREF_TAG)
×
559
        else
560
            serialize(s, kws)
×
561
        end
562
    else
563
        writetag(s.io, UNDEFREF_TAG)
×
564
    end
565
    nothing
×
566
end
567

568
# decide whether to send all data for a type (instead of just its name)
569
function should_send_whole_type(s, t::DataType)
570
    tn = t.name
907✔
571
    # TODO improve somehow?
572
    # send whole type for anonymous functions in Main
573
    name = tn.singletonname
907✔
574
    mod = tn.module
907✔
575
    mod === __deserialized_types__ && return true
907✔
576
    isanonfunction = mod === Main && # only Main
907✔
577
        t.super === Function && # only Functions
578
        unsafe_load(unsafe_convert(Ptr{UInt8}, tn.name)) == UInt8('#') && # hidden type
579
        (!isdefined(mod, name) || t != typeof(getglobal(mod, name))) # XXX: 95% accurate test for this being an inner function
580
        # TODO: more accurate test? (tn.name !== "#" name)
581
    return isanonfunction
907✔
582
end
583

584
function serialize_type_data(s, @nospecialize(t::DataType))
907✔
585
    whole = should_send_whole_type(s, t)
1,814✔
586
    iswrapper = (t === unwrap_unionall(t.name.wrapper))
907✔
587
    if whole && iswrapper
907✔
588
        writetag(s.io, WRAPPER_DATATYPE_TAG)
×
589
        serialize(s, t.name)
×
590
        return
×
591
    end
592
    serialize_cycle(s, t) && return
907✔
593
    if whole
34✔
594
        writetag(s.io, FULL_DATATYPE_TAG)
×
595
        serialize(s, t.name)
×
596
    else
597
        writetag(s.io, DATATYPE_TAG)
34✔
598
        serialize(s, nameof(t))
34✔
599
        serialize(s, parentmodule(t))
34✔
600
    end
601
    if !isempty(t.parameters)
34✔
602
        if iswrapper
23✔
603
            write(s.io, Int32(0))
×
604
        else
605
            write(s.io, Int32(length(t.parameters)))
23✔
606
            for p in t.parameters
46✔
607
                serialize(s, p)
65✔
608
            end
65✔
609
        end
610
    end
611
    nothing
34✔
612
end
613

614
function serialize(s::AbstractSerializer, t::DataType)
57✔
615
    tag = sertag(t)
4,252✔
616
    tag > 0 && return write_as_tag(s.io, tag)
57✔
617
    if t === Tuple
13✔
618
        # `sertag` is not able to find types === to `Tuple` because they
619
        # will not have been hash-consed. Plus `serialize_type_data` does not
620
        # handle this case correctly, since Tuple{} != Tuple. `Tuple` is the
621
        # only type with this property. issue #15849
622
        return write_as_tag(s.io, TUPLE_TAG)
×
623
    end
624
    serialize_type_data(s, t)
13✔
625
end
626

627
function serialize_type(s::AbstractSerializer, @nospecialize(t::DataType), ref::Bool = false)
894✔
628
    tag = sertag(t)
148,404✔
629
    tag > 0 && return writetag(s.io, tag)
894✔
630
    writetag(s.io, ref ? REF_OBJECT_TAG : OBJECT_TAG)
894✔
631
    serialize_type_data(s, t)
894✔
632
end
633

634
function serialize(s::AbstractSerializer, n::Int32)
635
    if 0 <= n <= (n_int_literals-1)
×
636
        write(s.io, UInt8(ZERO32_TAG+n))
×
637
    else
638
        writetag(s.io, INT32_TAG)
×
639
        write(s.io, n)
×
640
    end
641
    nothing
×
642
end
643

644
function serialize(s::AbstractSerializer, n::Int64)
36✔
645
    if 0 <= n <= (n_int_literals-1)
36✔
646
        write(s.io, UInt8(ZERO64_TAG+n))
22✔
647
    elseif typemin(Int32) <= n <= typemax(Int32)
14✔
648
        writetag(s.io, SHORTINT64_TAG)
14✔
649
        write(s.io, Int32(n))
14✔
650
    else
651
        writetag(s.io, INT64_TAG)
×
652
        write(s.io, n)
×
653
    end
654
    nothing
36✔
655
end
656

657
for i in 0:13
658
    tag = Int32(INT8_TAG + i)
659
    ty = TAGS[tag]
660
    (ty === Int32 || ty === Int64) && continue
661
    @eval serialize(s::AbstractSerializer, n::$ty) = (writetag(s.io, $tag); write(s.io, n); nothing)
505✔
662
end
663

664
serialize(s::AbstractSerializer, ::Type{Bottom}) = write_as_tag(s.io, BOTTOM_TAG)
10✔
665

666
function serialize(s::AbstractSerializer, u::UnionAll)
×
667
    writetag(s.io, UNIONALL_TAG)
×
668
    n = 0; t = u
×
669
    while isa(t, UnionAll)
×
670
        t = t.body
×
671
        n += 1
×
672
    end
×
673
    if isa(t, DataType) && t === unwrap_unionall(t.name.wrapper)
×
674
        write(s.io, UInt8(1))
×
675
        write(s.io, Int16(n))
×
676
        serialize(s, t)
×
677
    else
678
        write(s.io, UInt8(0))
×
679
        serialize(s, u.var)
×
680
        serialize(s, u.body)
×
681
    end
682
end
683

684
serialize(s::AbstractSerializer, @nospecialize(x)) = serialize_any(s, x)
419✔
685

686
function serialize(s::AbstractSerializer, x::Core.AddrSpace)
×
687
    serialize_type(s, typeof(x))
×
688
    write(s.io, Core.bitcast(UInt8, x))
×
689
end
690

691
function serialize_any(s::AbstractSerializer, @nospecialize(x))
422✔
692
    tag = sertag(x)
67,412✔
693
    if tag > 0
422✔
694
        return write_as_tag(s.io, tag)
30✔
695
    end
696
    t = typeof(x)::DataType
392✔
697
    if isprimitivetype(t)
392✔
698
        serialize_type(s, t)
×
699
        write(s.io, x)
×
700
    else
701
        if ismutable(x)
392✔
702
            serialize_cycle(s, x) && return
×
703
            serialize_type(s, t, true)
×
704
        else
705
            serialize_type(s, t, false)
392✔
706
        end
707
        nf = nfields(x)
392✔
708
        for i in 1:nf
392✔
709
            if isdefined(x, i)
388✔
710
                serialize(s, getfield(x, i))
388✔
711
            else
712
                writetag(s.io, UNDEFREF_TAG)
×
713
            end
714
        end
388✔
715
    end
716
    nothing
392✔
717
end
718

719
"""
720
    Serialization.writeheader(s::AbstractSerializer)
721

722
Write an identifying header to the specified serializer. The header consists of
723
8 bytes as follows:
724

725
| Offset | Description                                     |
726
|:-------|:------------------------------------------------|
727
|   0    | tag byte (0x37)                                 |
728
|   1-2  | signature bytes "JL"                            |
729
|   3    | protocol version                                |
730
|   4    | bits 0-1: endianness: 0 = little, 1 = big       |
731
|   4    | bits 2-3: platform: 0 = 32-bit, 1 = 64-bit      |
732
|   5-7  | reserved                                        |
733
"""
734
function writeheader(s::AbstractSerializer)
1✔
735
    io = s.io
1✔
736
    writetag(io, HEADER_TAG)
1✔
737
    write(io, "JL")  # magic bytes
1✔
738
    write(io, UInt8(ser_version))
1✔
739
    endianness = (ENDIAN_BOM == 0x04030201 ? 0 :
1✔
740
                  ENDIAN_BOM == 0x01020304 ? 1 :
741
                  error("unsupported endianness in serializer"))
742
    machine = (sizeof(Int) == 4 ? 0 :
1✔
743
               sizeof(Int) == 8 ? 1 :
744
               error("unsupported word size in serializer"))
745
    write(io, UInt8(endianness) | (UInt8(machine) << 2))
1✔
746
    write(io, [0x00,0x00,0x00]) # 3 reserved bytes
3✔
747
    nothing
1✔
748
end
749

750
function readheader(s::AbstractSerializer)
1✔
751
    # Tag already read
752
    io = s.io
1✔
753
    m1 = read(io, UInt8)
1✔
754
    m2 = read(io, UInt8)
1✔
755
    if m1 != UInt8('J') || m2 != UInt8('L')
2✔
756
        error("Unsupported serialization format (got header magic bytes $m1 $m2)")
×
757
    end
758
    version    = read(io, UInt8)
1✔
759
    flags      = read(io, UInt8)
1✔
760
    reserved1  = read(io, UInt8)
1✔
761
    reserved2  = read(io, UInt8)
1✔
762
    reserved3  = read(io, UInt8)
1✔
763
    endianflag = flags & 0x3
1✔
764
    wordflag   = (flags >> 2) & 0x3
1✔
765
    wordsize = wordflag == 0 ? 4 :
2✔
766
               wordflag == 1 ? 8 :
767
               error("Unknown word size flag in header")
768
    endian_bom = endianflag == 0 ? 0x04030201 :
1✔
769
                 endianflag == 1 ? 0x01020304 :
770
                 error("Unknown endianness flag in header")
771
    # Check protocol compatibility.
772
    endian_bom == ENDIAN_BOM  || error("Serialized byte order mismatch ($(repr(endian_bom)))")
1✔
773
    # We don't check wordsize == sizeof(Int) here, as Int is encoded concretely
774
    # as Int32 or Int64, which should be enough to correctly deserialize a range
775
    # of data structures between Julia versions.
776
    if version > ser_version
1✔
777
        error("""Cannot read stream serialized with a newer version of Julia.
×
778
                 Got data version $version > current version $ser_version""")
779
    end
780
    s.version = version
1✔
781
    return
1✔
782
end
783

784
"""
785
    serialize(stream::IO, value)
786

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

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

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

804
In some cases, the word size (32- or 64-bit) of the reading and writing machines must match.
805
In rarer cases the OS or architecture must also match, for example when using packages
806
that contain platform-dependent code.
807
"""
808
function serialize(s::IO, x)
1✔
809
    ss = Serializer(s)
1✔
810
    writeheader(ss)
1✔
811
    serialize(ss, x)
1✔
812
end
813

814
"""
815
    serialize(filename::AbstractString, value)
816

817
Open a file and serialize the given value to it.
818

819
!!! compat "Julia 1.1"
820
    This method is available as of Julia 1.1.
821
"""
822
serialize(filename::AbstractString, x) = open(io->serialize(io, x), filename, "w")
2✔
823

824
## deserializing values ##
825

826
"""
827
    deserialize(stream)
828

829
Read a value written by [`serialize`](@ref). `deserialize` assumes the binary data read from
830
`stream` is correct and has been serialized by a compatible implementation of [`serialize`](@ref).
831
`deserialize` is designed for simplicity and performance, and so does not validate
832
the data read. Malformed data can result in process termination. The caller must ensure
833
the integrity and correctness of data read from `stream`.
834
"""
835
deserialize(s::IO) = deserialize(Serializer(s))
1✔
836

837
"""
838
    deserialize(filename::AbstractString)
839

840
Open a file and deserialize its contents.
841

842
!!! compat "Julia 1.1"
843
    This method is available as of Julia 1.1.
844
"""
845
deserialize(filename::AbstractString) = open(deserialize, filename)
1✔
846

847
function deserialize(s::AbstractSerializer)
1,886✔
848
    handle_deserialize(s, Int32(read(s.io, UInt8)::UInt8))
8,937✔
849
end
850

851
function deserialize_cycle(s::AbstractSerializer, @nospecialize(x))
502✔
852
    slot = pop!(s.pending_refs)
502✔
853
    s.table[slot] = x
502✔
854
    nothing
502✔
855
end
856

857
# optimized version of:
858
#     slot = s.counter; s.counter += 1
859
#     push!(s.pending_refs, slot)
860
#     slot = pop!(s.pending_refs)
861
#     s.table[slot] = x
862
function resolve_ref_immediately(s::AbstractSerializer, @nospecialize(x))
863
    s.table[s.counter] = x
25✔
864
    s.counter += 1
25✔
865
    nothing
25✔
866
end
867

868
function gettable(s::AbstractSerializer, id::Int)
869
    get(s.table, id) do
3,526✔
870
        errmsg = """Inconsistent Serializer state when deserializing.
×
871
            Attempt to access internal table with key $id failed.
872

873
            This might occur if the Serializer contexts when serializing and deserializing are inconsistent.
874
            In particular, if multiple serialize calls use the same Serializer object then
875
            the corresponding deserialize calls should also use the same Serializer object.
876
        """
877
        error(errmsg)
×
878
    end
879
end
880

881
# deserialize_ is an internal function to dispatch on the tag
882
# describing the serialized representation. the number of
883
# representations is fixed, so deserialize_ does not get extended.
884
function handle_deserialize(s::AbstractSerializer, b::Int32)
9,730✔
885
    if b == 0
9,730✔
886
        return desertag(Int32(read(s.io, UInt8)::UInt8))
18✔
887
    end
888
    if b >= VALUE_TAGS
9,712✔
889
        return desertag(b)
186✔
890
    elseif b == TUPLE_TAG
9,526✔
891
        return deserialize_tuple(s, Int(read(s.io, UInt8)::UInt8))
8✔
892
    elseif b == SHORTBACKREF_TAG
9,518✔
893
        id = read(s.io, UInt16)::UInt16
3,526✔
894
        return gettable(s, Int(id))
3,526✔
895
    elseif b == BACKREF_TAG
5,992✔
896
        id = read(s.io, Int32)::Int32
×
897
        return gettable(s, Int(id))
×
898
    elseif b == ARRAY_TAG
5,992✔
899
        return deserialize_array(s)
12✔
900
    elseif b == DATATYPE_TAG
5,980✔
901
        return deserialize_datatype(s, false)
34✔
902
    elseif b == FULL_DATATYPE_TAG
5,946✔
903
        return deserialize_datatype(s, true)
×
904
    elseif b == WRAPPER_DATATYPE_TAG
5,946✔
905
        tname = deserialize(s)::Core.TypeName
×
906
        return unwrap_unionall(tname.wrapper)
×
907
    elseif b == OBJECT_TAG
5,946✔
908
        t = deserialize(s)
392✔
909
        if t === Missing
392✔
910
            return missing
×
911
        end
912
        return deserialize(s, t)
392✔
913
    elseif b == REF_OBJECT_TAG
5,554✔
914
        slot = s.counter; s.counter += 1
502✔
915
        push!(s.pending_refs, slot)
502✔
916
        t = deserialize(s)
502✔
917
        return deserialize(s, t)
502✔
918
    elseif b == SHARED_REF_TAG
5,052✔
919
        slot = s.counter; s.counter += 1
718✔
920
        obj = deserialize(s)
718✔
921
        s.table[slot] = obj
718✔
922
        return obj
718✔
923
    elseif b == SYMBOL_TAG
4,334✔
924
        return deserialize_symbol(s, Int(read(s.io, UInt8)::UInt8))
44✔
925
    elseif b == SHORTINT64_TAG
4,290✔
926
        return Int64(read(s.io, Int32)::Int32)
14✔
927
    elseif b == EXPR_TAG
4,276✔
928
        return deserialize_expr(s, Int(read(s.io, UInt8)::UInt8))
×
929
    elseif b == MODULE_TAG
4,276✔
930
        return deserialize_module(s)
34✔
931
    elseif b == STRING_TAG
4,242✔
932
        return deserialize_string(s, Int(read(s.io, UInt8)::UInt8))
3,734✔
933
    elseif b == LONGSTRING_TAG
508✔
934
        return deserialize_string(s, Int(read(s.io, Int64)::Int64))
2✔
935
    elseif b == SIMPLEVECTOR_TAG
506✔
936
        return deserialize_svec(s)
×
937
    elseif b == GLOBALREF_TAG
506✔
938
        return GlobalRef(deserialize(s)::Module, deserialize(s)::Symbol)
×
939
    elseif b == FULL_GLOBALREF_TAG
506✔
940
        ty = deserialize(s)
×
941
        tn = unwrap_unionall(ty).name
×
942
        return GlobalRef(tn.module, tn.name)
×
943
    elseif b == LONGTUPLE_TAG
506✔
944
        return deserialize_tuple(s, Int(read(s.io, Int32)::Int32))
×
945
    elseif b == LONGEXPR_TAG
506✔
946
        return deserialize_expr(s, Int(read(s.io, Int32)::Int32))
×
947
    elseif b == LONGBACKREF_TAG
506✔
948
        id = read(s.io, Int64)::Int64
×
949
        return gettable(s, Int(id))
×
950
    elseif b == LONGSYMBOL_TAG
506✔
951
        return deserialize_symbol(s, Int(read(s.io, Int32)::Int32))
×
952
    elseif b == HEADER_TAG
506✔
953
        readheader(s)
1✔
954
        return deserialize(s)
1✔
955
    elseif b == INT8_TAG
505✔
956
        return read(s.io, Int8)
×
957
    elseif b == INT8_TAG+1
505✔
958
        return read(s.io, UInt8)
×
959
    elseif b == INT8_TAG+2
505✔
960
        return read(s.io, Int16)
×
961
    elseif b == INT8_TAG+3
505✔
962
        return read(s.io, UInt16)
×
963
    elseif b == INT32_TAG
505✔
964
        return read(s.io, Int32)
×
965
    elseif b == INT8_TAG+5
505✔
966
        return read(s.io, UInt32)
×
967
    elseif b == INT64_TAG
505✔
968
        return read(s.io, Int64)
×
969
    elseif b == INT8_TAG+7
505✔
970
        return read(s.io, UInt64)
×
971
    elseif b == INT8_TAG+8
505✔
972
        return read(s.io, Int128)
×
973
    elseif b == INT8_TAG+9
505✔
974
        return read(s.io, UInt128)
363✔
975
    elseif b == INT8_TAG+10
142✔
976
        return read(s.io, Float16)
×
977
    elseif b == INT8_TAG+11
142✔
978
        return read(s.io, Float32)
×
979
    elseif b == INT8_TAG+12
142✔
980
        return read(s.io, Float64)
142✔
981
    elseif b == INT8_TAG+13
×
982
        return read(s.io, Char)
×
983
    elseif b == IDDICT_TAG
×
984
        slot = s.counter; s.counter += 1
×
985
        push!(s.pending_refs, slot)
×
986
        t = deserialize(s)
×
987
        return deserialize_dict(s, t)
×
988
    end
989
    t = desertag(b)::DataType
×
990
    if ismutabletype(t) && length(t.types) > 0  # manual specialization of fieldcount
×
991
        slot = s.counter; s.counter += 1
×
992
        push!(s.pending_refs, slot)
×
993
    end
994
    return deserialize(s, t)
×
995
end
996

997
function deserialize_symbol(s::AbstractSerializer, len::Int)
44✔
998
    str = Base._string_n(len)
44✔
999
    unsafe_read(s.io, pointer(str), len)
44✔
1000
    sym = Symbol(str)
44✔
1001
    if len > 7
44✔
1002
        resolve_ref_immediately(s, sym)
25✔
1003
    end
1004
    return sym
44✔
1005
end
1006

1007
deserialize_tuple(s::AbstractSerializer, len) = ntupleany(i->deserialize(s), len)
20✔
1008

1009
function deserialize_svec(s::AbstractSerializer)
×
1010
    n = read(s.io, Int32)
×
1011
    svec(Any[ deserialize(s) for i=1:n ]...)
×
1012
end
1013

1014
function deserialize_module(s::AbstractSerializer)
34✔
1015
    mkey = deserialize(s)
34✔
1016
    if isa(mkey, Tuple)
34✔
1017
        # old version, TODO: remove
1018
        if mkey === ()
×
1019
            return Main
×
1020
        end
1021
        m = Base.root_module(mkey[1])
×
1022
        for i = 2:length(mkey)
×
1023
            m = getglobal(m, mkey[i])::Module
×
1024
        end
×
1025
    else
1026
        name = String(deserialize(s)::Symbol)
34✔
1027
        pkg = (mkey === nothing) ? Base.PkgId(name) : Base.PkgId(Base.UUID(mkey), name)
38✔
1028
        m = Base.root_module(pkg)
34✔
1029
        mname = deserialize(s)
34✔
1030
        while mname !== ()
36✔
1031
            m = getglobal(m, mname)::Module
2✔
1032
            mname = deserialize(s)
2✔
1033
        end
2✔
1034
    end
1035
    return m
34✔
1036
end
1037

1038
function deserialize(s::AbstractSerializer, ::Type{Method})
×
1039
    lnumber = read(s.io, UInt64)
×
1040
    meth = lookup_object_number(s, lnumber)
×
1041
    if meth !== nothing
×
1042
        meth = meth::Method
×
1043
        makenew = false
×
1044
    else
1045
        meth = ccall(:jl_new_method_uninit, Ref{Method}, (Any,), Main)
×
1046
        makenew = true
×
1047
    end
1048
    deserialize_cycle(s, meth)
×
1049
    mod = deserialize(s)::Module
×
1050
    name = deserialize(s)::Symbol
×
1051
    file = deserialize(s)::Symbol
×
1052
    line = deserialize(s)::Int32
×
1053
    sig = deserialize(s)::Type
×
1054
    syms = deserialize(s)
×
1055
    if syms isa SimpleVector
×
1056
        # < v1.2
1057
        _ambig = deserialize(s)
×
1058
    else
1059
        slot_syms = syms::String
×
1060
    end
1061
    nargs = deserialize(s)::Int32
×
1062
    isva = deserialize(s)::Bool
×
1063
    is_for_opaque_closure = false
×
1064
    nospecializeinfer = false
×
1065
    constprop = 0x00
×
1066
    purity = 0x0000
×
1067
    template_or_is_opaque = deserialize(s)
×
1068
    if isa(template_or_is_opaque, Bool)
×
1069
        is_for_opaque_closure = template_or_is_opaque
×
1070
        if format_version(s) >= 24
×
1071
            nospecializeinfer = deserialize(s)::Bool
×
1072
        end
1073
        if format_version(s) >= 14
×
1074
            constprop = deserialize(s)::UInt8
×
1075
        end
1076
        if format_version(s) >= 26
×
1077
            purity = deserialize(s)::UInt16
×
1078
        elseif format_version(s) >= 17
×
1079
            purity = UInt16(deserialize(s)::UInt8)
×
1080
        end
1081
        template = deserialize(s)
×
1082
    else
1083
        template = template_or_is_opaque
×
1084
    end
1085
    generator = deserialize(s)
×
1086
    recursion_relation = nothing
×
1087
    if format_version(s) >= 15
×
1088
        recursion_relation = deserialize(s)
×
1089
    end
1090
    if makenew
×
1091
        meth.module = mod
×
1092
        meth.debuginfo = NullDebugInfo
×
1093
        meth.name = name
×
1094
        meth.file = file
×
1095
        meth.line = line
×
1096
        meth.sig = sig
×
1097
        meth.nargs = nargs
×
1098
        meth.isva = isva
×
1099
        meth.is_for_opaque_closure = is_for_opaque_closure
×
1100
        meth.nospecializeinfer = nospecializeinfer
×
1101
        meth.constprop = constprop
×
1102
        meth.purity = purity
×
1103
        if template !== nothing
×
1104
            # TODO: compress template
1105
            template = template::CodeInfo
×
1106
            if format_version(s) < 29
×
1107
                template.nargs = nargs
×
1108
                template.isva = isva
×
1109
            end
1110
            meth.source = template
×
1111
            meth.debuginfo = template.debuginfo
×
1112
            if !@isdefined(slot_syms)
×
1113
                slot_syms = ccall(:jl_compress_argnames, Ref{String}, (Any,), meth.source.slotnames)
×
1114
            end
1115
        end
1116
        meth.slot_syms = slot_syms
×
1117
        if generator !== nothing
×
1118
            meth.generator = generator
×
1119
        end
1120
        if recursion_relation !== nothing
×
1121
            meth.recursion_relation = recursion_relation
×
1122
        end
1123
        if !is_for_opaque_closure
×
1124
            mt = Core.GlobalMethods
×
1125
            if nothing === ccall(:jl_methtable_lookup, Any, (Any, UInt), sig, Base.get_world_counter()) # XXX: quite sketchy?
×
1126
                ccall(:jl_method_table_insert, Cvoid, (Any, Any, Ptr{Cvoid}), mt, meth, C_NULL)
×
1127
            end
1128
        end
1129
        remember_object(s, meth, lnumber)
×
1130
    end
1131
    return meth
×
1132
end
1133

1134
function deserialize(s::AbstractSerializer, ::Type{Core.MethodTable})
×
1135
    name = deserialize(s)::Symbol
×
1136
    mod = deserialize(s)::Module
×
1137
    return getglobal(mod, name)::Core.MethodTable
×
1138
end
1139

1140
function deserialize(s::AbstractSerializer, ::Type{Core.MethodInstance})
×
1141
    linfo = ccall(:jl_new_method_instance_uninit, Ref{Core.MethodInstance}, (Ptr{Cvoid},), C_NULL)
×
1142
    deserialize_cycle(s, linfo)
×
1143
    if format_version(s) < 28
×
1144
        tag = Int32(read(s.io, UInt8)::UInt8)
×
1145
        if tag != UNDEFREF_TAG
×
1146
            code = handle_deserialize(s, tag)::CodeInfo
×
1147
            ci = ccall(:jl_new_codeinst_for_uninferred, Ref{CodeInstance}, (Any, Any), linfo, code)
×
1148
            @atomic linfo.cache = ci
×
1149
        end
1150
    end
1151
    tag = Int32(read(s.io, UInt8)::UInt8)
×
1152
    if tag != UNDEFREF_TAG
×
1153
        # for reading files prior to v1.2
1154
        handle_deserialize(s, tag)
×
1155
    end
1156
    linfo.sparam_vals = deserialize(s)::SimpleVector
×
1157
    _rettype = deserialize(s)  # for backwards compat
×
1158
    linfo.specTypes = deserialize(s)
×
1159
    linfo.def = deserialize(s)
×
1160
    return linfo
×
1161
end
1162

1163
function deserialize(s::AbstractSerializer, ::Type{Core.LineInfoNode})
×
1164
    mod = deserialize(s)
×
1165
    if mod isa Module
×
1166
        method = deserialize(s)
×
1167
    else
1168
        # files post v1.2 and pre v1.6 are broken
1169
        method = mod
×
1170
        mod = Main
×
1171
    end
1172
    return Core.LineInfoNode(mod, method, deserialize(s)::Symbol, Int32(deserialize(s)::Union{Int32, Int}), Int32(deserialize(s)::Union{Int32, Int}))
×
1173
end
1174

1175

1176
function deserialize(s::AbstractSerializer, ::Type{PhiNode})
×
1177
    edges = deserialize(s)
×
1178
    if edges isa Vector{Any}
×
1179
        edges = Vector{Int32}(edges)
×
1180
    end
1181
    values = deserialize(s)::Vector{Any}
×
1182
    return PhiNode(edges, values)
×
1183
end
1184

1185
function deserialize(s::AbstractSerializer, ::Type{CodeInfo})
×
1186
    ci = ccall(:jl_new_code_info_uninit, Ref{CodeInfo}, ())
×
1187
    deserialize_cycle(s, ci)
×
1188
    code = deserialize(s)::Vector{Any}
×
1189
    ci.code = code
×
1190
    ci.debuginfo = NullDebugInfo
×
1191
    # allow older-style IR with return and gotoifnot Exprs
1192
    for i in 1:length(code)
×
1193
        stmt = code[i]
×
1194
        if isa(stmt, Expr)
×
1195
            ex = stmt::Expr
×
1196
            if ex.head === :return
×
1197
                code[i] = ReturnNode(isempty(ex.args) ? nothing : ex.args[1])
×
1198
            elseif ex.head === :gotoifnot
×
1199
                code[i] = GotoIfNot(ex.args[1], ex.args[2])
×
1200
            end
1201
        end
1202
    end
×
1203
    _x = deserialize(s)
×
1204
    have_debuginfo = _x isa Core.DebugInfo
×
1205
    if have_debuginfo
×
1206
        ci.debuginfo = _x
×
1207
    else
1208
        codelocs = _x::Vector{Int32}
×
1209
        # TODO: convert codelocs to debuginfo format?
1210
    end
1211
    _x = deserialize(s)
×
1212
    if _x isa Array || _x isa Int
×
1213
        pre_12 = false
×
1214
    else
1215
        pre_12 = true
×
1216
        # < v1.2
1217
        ci.method_for_inference_limit_heuristics = _x
×
1218
        _x = deserialize(s)
×
1219
    end
1220
    ci.ssavaluetypes = _x
×
1221
    if pre_12
×
1222
        linetable = deserialize(s)
×
1223
        # TODO: convert linetable to debuginfo format?
1224
    end
1225
    ssaflags = deserialize(s)
×
1226
    if length(ssaflags) ≠ length(code)
×
1227
        # make sure the length of `ssaflags` matches that of `code`
1228
        # so that the latest inference doesn't throw on IRs serialized from old versions
1229
        ssaflags = UInt32[0x00 for _ in 1:length(code)]
×
1230
    elseif eltype(ssaflags) != UInt32
×
1231
        ssaflags = map(UInt32, ssaflags)
×
1232
    end
1233
    ci.ssaflags = ssaflags
×
1234
    if pre_12
×
1235
        ci.slotflags = deserialize(s)
×
1236
    else
1237
        if format_version(s) <= 26
×
1238
            ci.method_for_inference_limit_heuristics = deserialize(s)
×
1239
        end
1240
        if !have_debuginfo # pre v1.11 format
×
1241
            linetable = deserialize(s)
×
1242
            # TODO: convert linetable to debuginfo format?
1243
        end
1244
    end
1245
    ci.slotnames = deserialize(s)
×
1246
    if !pre_12
×
1247
        ci.slotflags = deserialize(s)
×
1248
        ci.slottypes = deserialize(s)
×
1249
        ci.rettype = deserialize(s)
×
1250
        ci.parent = deserialize(s)
×
1251
        world_or_edges = deserialize(s)
×
1252
        pre_13 = isa(world_or_edges, Union{UInt, Int})
×
1253
        if pre_13
×
1254
            ci.min_world = reinterpret(UInt, world_or_edges)
×
1255
            ci.max_world = reinterpret(UInt, deserialize(s))
×
1256
        else
1257
            ci.edges = world_or_edges
×
1258
            ci.min_world = deserialize(s)::UInt
×
1259
            ci.max_world = deserialize(s)::UInt
×
1260
        end
1261
        if format_version(s) >= 26
×
1262
            ci.method_for_inference_limit_heuristics = deserialize(s)
×
1263
        end
1264
    end
1265
    if format_version(s) <= 26
×
1266
        deserialize(s)::Bool # inferred
×
1267
    end
1268
    if format_version(s) < 22
×
1269
        inlining_cost = deserialize(s)
×
1270
        if isa(inlining_cost, Bool)
×
1271
            Core.Compiler.set_inlineable!(ci, inlining_cost)
×
1272
        else
1273
            ci.inlining_cost = inlining_cost
×
1274
        end
1275
    end
1276
    if format_version(s) >= 29
×
1277
        ci.nargs = deserialize(s)
×
1278
    end
1279
    ci.propagate_inbounds = deserialize(s)
×
1280
    if format_version(s) < 23
×
1281
        deserialize(s) # `pure` field has been removed
×
1282
    end
1283
    if format_version(s) >= 20
×
1284
        ci.has_fcall = deserialize(s)
×
1285
    end
1286
    if format_version(s) >= 30
×
1287
        ci.has_image_globalref = deserialize(s)::Bool
×
1288
    end
1289
    if format_version(s) >= 24
×
1290
        ci.nospecializeinfer = deserialize(s)::Bool
×
1291
    end
1292
    if format_version(s) >= 29
×
1293
        ci.isva = deserialize(s)::Bool
×
1294
    end
1295
    if format_version(s) >= 21
×
1296
        ci.inlining = deserialize(s)::UInt8
×
1297
    end
1298
    if format_version(s) >= 14
×
1299
        ci.constprop = deserialize(s)::UInt8
×
1300
    end
1301
    if format_version(s) >= 26
×
1302
        ci.purity = deserialize(s)::UInt16
×
1303
    elseif format_version(s) >= 17
×
1304
        ci.purity = deserialize(s)::UInt8
×
1305
    end
1306
    if format_version(s) >= 22
×
1307
        ci.inlining_cost = deserialize(s)::UInt16
×
1308
    end
1309
    ci.debuginfo = NullDebugInfo
×
1310
    return ci
×
1311
end
1312

1313
import Core: NullDebugInfo
1314

1315
if Int === Int64
1316
const OtherInt = Int32
1317
else
1318
const OtherInt = Int64
1319
end
1320

1321
function deserialize_array(s::AbstractSerializer)
12✔
1322
    slot = s.counter; s.counter += 1
12✔
1323
    d1 = deserialize(s)
12✔
1324
    if isa(d1, Type)
12✔
1325
        elty = d1
12✔
1326
        d1 = deserialize(s)
12✔
1327
    else
1328
        elty = UInt8
×
1329
    end
1330
    if isa(d1, Int32) || isa(d1, Int64)
24✔
1331
        if elty !== Bool && isbitstype(elty)
12✔
1332
            a = Vector{elty}(undef, d1)
4✔
1333
            s.table[slot] = a
4✔
1334
            return read!(s.io, a)
4✔
1335
        end
1336
        dims = (Int(d1),)
16✔
1337
    elseif d1 isa Dims
×
1338
        dims = d1::Dims
×
1339
    else
1340
        dims = convert(Dims, d1::Tuple{Vararg{OtherInt}})::Dims
×
1341
    end
1342
    if isbitstype(elty)
8✔
1343
        n = prod(dims)::Int
×
1344
        if elty === Bool && n > 0
×
1345
            A = Array{Bool, length(dims)}(undef, dims)
×
1346
            i = 1
×
1347
            while i <= n
×
1348
                b = read(s.io, UInt8)::UInt8
×
1349
                v = (b >> 7) != 0
×
1350
                count = b & 0x7f
×
1351
                nxt = i + count
×
1352
                while i < nxt
×
1353
                    A[i] = v
×
1354
                    i += 1
×
1355
                end
×
1356
            end
×
1357
        else
1358
            A = read!(s.io, Array{elty}(undef, dims))
×
1359
        end
1360
        s.table[slot] = A
×
1361
        return A
×
1362
    end
1363
    A = Array{elty, length(dims)}(undef, dims)
8✔
1364
    s.table[slot] = A
8✔
1365
    sizehint!(s.table, s.counter + div(length(A)::Int,4))
9✔
1366
    deserialize_fillarray!(A, s)
8✔
1367
    return A
8✔
1368
end
1369

1370
function deserialize_fillarray!(A::Union{Array{T},Memory{T}}, s::AbstractSerializer) where {T}
8✔
1371
    for i = eachindex(A)
8✔
1372
        tag = Int32(read(s.io, UInt8)::UInt8)
365✔
1373
        if tag != UNDEFREF_TAG
365✔
1374
            @inbounds A[i] = handle_deserialize(s, tag)
365✔
1375
        end
1376
    end
725✔
1377
    return A
8✔
1378
end
1379

1380
function deserialize(s::AbstractSerializer, X::Type{Memory{T}} where T)
×
1381
    slot = pop!(s.pending_refs) # e.g. deserialize_cycle
×
1382
    n = deserialize(s)::Int
×
1383
    elty = eltype(X)
×
1384
    if isbitstype(elty)
×
1385
        A = X(undef, n)
×
1386
        if X === Memory{Bool}
×
1387
            i = 1
×
1388
            while i <= n
×
1389
                b = read(s.io, UInt8)::UInt8
×
1390
                v = (b >> 7) != 0
×
1391
                count = b & 0x7f
×
1392
                nxt = i + count
×
1393
                while i < nxt
×
1394
                    A[i] = v
×
1395
                    i += 1
×
1396
                end
×
1397
            end
×
1398
        else
1399
            A = read!(s.io, A)::X
×
1400
        end
1401
        s.table[slot] = A
×
1402
        return A
×
1403
    end
1404
    A = X(undef, n)
×
1405
    s.table[slot] = A
×
1406
    sizehint!(s.table, s.counter + div(n, 4))
×
1407
    deserialize_fillarray!(A, s)
×
1408
    return A
×
1409
end
1410

1411
function deserialize(s::AbstractSerializer, X::Type{MemoryRef{T}} where T)
×
1412
    x = Core.memoryref(deserialize(s))::X
×
1413
    i = deserialize(s)::Int
×
1414
    i == 2 || (x = Core.memoryref(x, i, true))
×
1415
    return x::X
×
1416
end
1417

1418
function deserialize(s::AbstractSerializer, X::Type{Core.AddrSpace{M}} where M)
×
1419
    Core.bitcast(X, read(s.io, UInt8))
×
1420
end
1421

1422
function deserialize_expr(s::AbstractSerializer, len)
×
1423
    e = Expr(:temp)
×
1424
    resolve_ref_immediately(s, e)
×
1425
    e.head = deserialize(s)::Symbol
×
1426
    e.args = Any[ deserialize(s) for i = 1:len ]
×
1427
    e
×
1428
end
1429

1430
module __deserialized_types__ end
1431

1432
function deserialize(s::AbstractSerializer, ::Type{Core.TypeName})
×
1433
    number = read(s.io, UInt64)
×
1434
    return deserialize_typename(s, number)
×
1435
end
1436

1437
function deserialize_typename(s::AbstractSerializer, number)
×
1438
    name = deserialize(s)::Symbol
×
1439
    tn = lookup_object_number(s, number)
×
1440
    if tn !== nothing
×
1441
        makenew = false
×
1442
    else
1443
        # reuse the same name for the type, if possible, for nicer debugging
1444
        tn_name = isdefined(__deserialized_types__, name) ? gensym() : name
×
1445
        tn = ccall(:jl_new_typename_in, Any, (Any, Any, Cint, Cint),
×
1446
                   tn_name, __deserialized_types__, false, false)
1447
        makenew = true
×
1448
    end
1449
    tn = tn::Core.TypeName
×
1450
    remember_object(s, tn, number)
×
1451
    deserialize_cycle(s, tn)
×
1452

1453
    names = deserialize(s)::SimpleVector
×
1454
    super = deserialize(s)::Type
×
1455
    parameters = deserialize(s)::SimpleVector
×
1456
    types = deserialize(s)::SimpleVector
×
1457
    attrs = Core.svec()
×
1458
    has_instance = deserialize(s)::Bool
×
1459
    abstr = deserialize(s)::Bool
×
1460
    mutabl = deserialize(s)::Bool
×
1461
    ninitialized = deserialize(s)::Int32
×
1462
    maxm = format_version(s) >= 18 ? deserialize(s)::UInt8 : UInt8(0)
×
1463

1464
    if makenew
×
1465
        # TODO: there's an unhanded cycle in the dependency graph at this point:
1466
        # while deserializing super and/or types, we may have encountered
1467
        # tn.wrapper and throw UndefRefException before we get to this point
1468
        ndt = ccall(:jl_new_datatype, Any, (Any, Any, Any, Any, Any, Any, Any, Cint, Cint, Cint),
×
1469
                    tn, tn.module, super, parameters, names, types, attrs,
1470
                    abstr, mutabl, ninitialized)
1471
        @assert tn == ndt.name
×
1472
        ccall(:jl_set_const, Cvoid, (Any, Any, Any), tn.module, tn.name, tn.wrapper)
×
1473
        ty = tn.wrapper
×
1474
        tn.max_methods = maxm
×
1475
        if has_instance
×
1476
            ty = ty::DataType
×
1477
            if !isdefined(ty, :instance)
×
1478
                singleton = ccall(:jl_new_struct, Any, (Any, Any...), ty)
×
1479
                # use setfield! directly to avoid `fieldtype` lowering expecting to see a Singleton object already on ty
1480
                ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), ty, Base.fieldindex(DataType, :instance)-1, singleton)
×
1481
            end
1482
        end
1483
    end
1484

1485
    tag = Int32(read(s.io, UInt8)::UInt8)
×
1486
    if tag != UNDEFREF_TAG
×
1487
        mtname = handle_deserialize(s, tag)
×
1488
        defs = deserialize(s)
×
1489
        maxa = deserialize(s)::Union{Int,Int32}
×
1490
        if makenew
×
1491
            tn.singletonname = mtname
×
1492
            setfield!(tn, :max_args, Int32(maxa), :monotonic)
×
1493
        end
1494
        tag = Int32(read(s.io, UInt8)::UInt8)
×
1495
        if tag != UNDEFREF_TAG
×
1496
            kws = handle_deserialize(s, tag)
×
1497
            if makenew && !(kws isa Vector{Method})
×
1498
                # old object format -- try to forward from old to new
1499
                @eval Core.kwcall(kwargs::NamedTuple, f::$ty, args...) = $kws(kwargs, f, args...)
×
1500
            end
1501
        end
1502
    end
1503
    return tn
×
1504
end
1505

1506
function deserialize_datatype(s::AbstractSerializer, full::Bool)
34✔
1507
    slot = s.counter; s.counter += 1
34✔
1508
    if full
34✔
1509
        tname = deserialize(s)::Core.TypeName
×
1510
        ty = tname.wrapper
×
1511
    else
1512
        name = deserialize(s)::Symbol
34✔
1513
        mod = deserialize(s)::Module
34✔
1514
        ty = getglobal(mod, name)
34✔
1515
    end
1516
    if isa(ty,DataType) && isempty(ty.parameters)
34✔
1517
        t = ty
11✔
1518
    else
1519
        np = Int(read(s.io, Int32)::Int32)
23✔
1520
        if np == 0
23✔
1521
            t = unwrap_unionall(ty)
×
1522
        elseif ty === Tuple
23✔
1523
            # note np==0 has its own tag
1524
            if np == 1
×
1525
                t = Tuple{deserialize(s)}
×
1526
            elseif np == 2
×
1527
                t = Tuple{deserialize(s), deserialize(s)}
×
1528
            elseif np == 3
×
1529
                t = Tuple{deserialize(s), deserialize(s), deserialize(s)}
×
1530
            elseif np == 4
×
1531
                t = Tuple{deserialize(s), deserialize(s), deserialize(s), deserialize(s)}
×
1532
            else
1533
                t = Tuple{Any[ deserialize(s) for i=1:np ]...}
×
1534
            end
1535
        else
1536
            t = ty
23✔
1537
            for i = 1:np
23✔
1538
                t = t{deserialize(s)}
65✔
1539
            end
65✔
1540
        end
1541
    end
1542
    s.table[slot] = t
34✔
1543
    return t
34✔
1544
end
1545

1546
function deserialize(s::AbstractSerializer, ::Type{UnionAll})
×
1547
    form = read(s.io, UInt8)
×
1548
    if form == 0
×
1549
        var = deserialize(s)
×
1550
        body = deserialize(s)
×
1551
        return UnionAll(var, body)
×
1552
    else
1553
        n = read(s.io, Int16)
×
1554
        t = deserialize(s)::DataType
×
1555
        w = t.name.wrapper
×
1556
        k = 0
×
1557
        while isa(w, UnionAll)
×
1558
            w = w.body
×
1559
            k += 1
×
1560
        end
×
1561
        w = t.name.wrapper
×
1562
        k -= n
×
1563
        while k > 0
×
1564
            w = w.body
×
1565
            k -= 1
×
1566
        end
×
1567
        return w
×
1568
    end
1569
end
1570

1571
function deserialize(s::AbstractSerializer, ::Type{Task})
×
1572
    t = Task(()->nothing)
×
1573
    deserialize_cycle(s, t)
×
1574
    t.code = deserialize(s)
×
1575
    t.storage = deserialize(s)
×
1576
    state = deserialize(s)
×
1577
    if state === :runnable
×
1578
        @atomic :release t._state = Base.task_state_runnable
×
1579
    elseif state === :done
×
1580
        @atomic :release t._state = Base.task_state_done
×
1581
    elseif state === :failed
×
1582
        @atomic :release t._state = Base.task_state_failed
×
1583
    else
1584
        @assert false
×
1585
    end
1586
    t.result = deserialize(s)
×
1587
    exc = deserialize(s)
×
1588
    if exc === nothing
×
1589
        t._isexception = false
×
1590
    elseif exc isa Bool
×
1591
        t._isexception = exc
×
1592
    else
1593
        t._isexception = true
×
1594
        t.result = exc
×
1595
    end
1596
    t
×
1597
end
1598

1599
function deserialize_string(s::AbstractSerializer, len::Int)
1600
    out = ccall(:jl_alloc_string, Ref{String}, (Csize_t,), len)
3,736✔
1601
    unsafe_read(s.io, pointer(out), len)
3,736✔
1602
    return out
3,736✔
1603
end
1604

1605
# default DataType deserializer
1606
function deserialize(s::AbstractSerializer, t::DataType)
392✔
1607
    nf = length(t.types)
392✔
1608
    if isprimitivetype(t)
392✔
1609
        return read(s.io, t)
×
1610
    elseif ismutabletype(t)
392✔
1611
        x = ccall(:jl_new_struct_uninit, Any, (Any,), t)
×
1612
        deserialize_cycle(s, x)
×
1613
        for i in 1:nf
×
1614
            tag = Int32(read(s.io, UInt8)::UInt8)
×
1615
            if tag != UNDEFREF_TAG
×
1616
                ccall(:jl_set_nth_field, Cvoid, (Any, Csize_t, Any), x, i-1, handle_deserialize(s, tag))
×
1617
            end
1618
        end
×
1619
        return x
×
1620
    elseif nf == 0
392✔
1621
        return ccall(:jl_new_struct_uninit, Any, (Any,), t)
20✔
1622
    else
1623
        na = nf
372✔
1624
        vflds = Vector{Any}(undef, nf)
372✔
1625
        for i in 1:nf
372✔
1626
            tag = Int32(read(s.io, UInt8)::UInt8)
388✔
1627
            if tag != UNDEFREF_TAG
388✔
1628
                f = handle_deserialize(s, tag)
388✔
1629
                na >= i && (vflds[i] = f)
388✔
1630
            else
1631
                na >= i && (na = i - 1) # rest of tail must be undefined values
×
1632
            end
1633
        end
404✔
1634
        return ccall(:jl_new_structv, Any, (Any, Ptr{Any}, UInt32), t, vflds, na)
372✔
1635
    end
1636
end
1637

1638
function deserialize_dict(s::AbstractSerializer, T::Type{<:AbstractDict})
502✔
1639
    n = read(s.io, Int32)
502✔
1640
    t = T(); sizehint!(t, n)
1,004✔
1641
    deserialize_cycle(s, t)
502✔
1642
    for i = 1:n
502✔
1643
        k = deserialize(s)
3,515✔
1644
        v = deserialize(s)
3,515✔
1645
        t[k] = v
3,515✔
1646
    end
6,528✔
1647
    return t
502✔
1648
end
1649

1650
function deserialize(s::AbstractSerializer, T::Type{Dict{K,V}}) where {K,V}
502✔
1651
    return deserialize_dict(s, T)
502✔
1652
end
1653

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

1656
function deserialize(s::AbstractSerializer, t::Type{Regex})
×
1657
    pattern = deserialize(s)
×
1658
    compile_options = deserialize(s)
×
1659
    match_options = deserialize(s)
×
1660
    return Regex(pattern, compile_options, match_options)
×
1661
end
1662

1663
## StackTraces
1664

1665
# provide a custom serializer that skips attempting to serialize the `outer_linfo`
1666
# which is likely to contain complex references, types, and module references
1667
# that may not exist on the receiver end
1668
function serialize(s::AbstractSerializer, frame::Base.StackTraces.StackFrame)
×
1669
    serialize_type(s, typeof(frame))
×
1670
    serialize(s, frame.func)
×
1671
    serialize(s, frame.file)
×
1672
    write(s.io, frame.line)
×
1673
    write(s.io, frame.from_c)
×
1674
    write(s.io, frame.inlined)
×
1675
    write(s.io, frame.pointer)
×
1676
    nothing
×
1677
end
1678

1679
function deserialize(s::AbstractSerializer, ::Type{Base.StackTraces.StackFrame})
×
1680
    func = deserialize(s)
×
1681
    file = deserialize(s)
×
1682
    line = read(s.io, Int)
×
1683
    from_c = read(s.io, Bool)
×
1684
    inlined = read(s.io, Bool)
×
1685
    pointer = read(s.io, UInt64)
×
1686
    return Base.StackTraces.StackFrame(func, file, line, nothing, from_c, inlined, pointer)
×
1687
end
1688

1689
function serialize(s::AbstractSerializer, lock::Base.AbstractLock)
×
1690
    # assert_havelock(lock)
1691
    serialize_cycle_header(s, lock)
×
1692
    nothing
×
1693
end
1694

1695
function deserialize(s::AbstractSerializer, ::Type{T}) where T<:Base.AbstractLock
×
1696
    lock = T()
×
1697
    deserialize_cycle(s, lock)
×
1698
    return lock
×
1699
end
1700

1701
function serialize(s::AbstractSerializer, cond::Base.GenericCondition)
×
1702
    serialize_cycle_header(s, cond) && return
×
1703
    serialize(s, cond.lock)
×
1704
    nothing
×
1705
end
1706

1707
function deserialize(s::AbstractSerializer, ::Type{T}) where T<:Base.GenericCondition
×
1708
    lock = deserialize(s)
×
1709
    cond = T(lock)
×
1710
    deserialize_cycle(s, cond)
×
1711
    return cond
×
1712
end
1713

1714
serialize(s::AbstractSerializer, l::LazyString) =
×
1715
    invoke(serialize, Tuple{AbstractSerializer,Any}, s, Base._LazyString((), string(l)))
1716

1717
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc