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

JuliaLang / julia / #38084

29 May 2025 04:37AM UTC coverage: 25.773% (+0.07%) from 25.705%
#38084

push

local

web-flow
test: Automatically install Revise for `revise-` targets (#58559)

This fixes #50256, by automatically installing a private copy of
`Revise` into test/deps, similar to the mechanism for Documenter in
make.jl. As in #58529, I made sure that this worked with both in-tree
and out-of-tree builds.

12850 of 49858 relevant lines covered (25.77%)

714696.95 hits per line

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

34.81
/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.cache)
×
473
    nothing
×
474
end
475

476
function serialize(s::AbstractSerializer, mc::Core.MethodCache)
×
477
    serialize_type(s, typeof(mc))
×
478
    serialize(s, mc.name)
×
479
    serialize(s, mc.module)
×
480
    nothing
×
481
end
482

483

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

686
serialize(s::AbstractSerializer, @nospecialize(x)) = serialize_any(s, x)
419✔
687

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

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

721
"""
722
    Serialization.writeheader(s::AbstractSerializer)
723

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

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

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

786
"""
787
    serialize(stream::IO, value)
788

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

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

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

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

816
"""
817
    serialize(filename::AbstractString, value)
818

819
Open a file and serialize the given value to it.
820

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

826
## deserializing values ##
827

828
"""
829
    deserialize(stream)
830

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

839
"""
840
    deserialize(filename::AbstractString)
841

842
Open a file and deserialize its contents.
843

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

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

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

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

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

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

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

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

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

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

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

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

1136
function deserialize(s::AbstractSerializer, ::Type{Core.MethodTable})
×
1137
    mc = deserialize(s)::Core.MethodCache
×
1138
    mc === Core.GlobalMethods.cache && return Core.GlobalMethods
×
1139
    return getglobal(mc.mod, mc.name)::Core.MethodTable
×
1140
end
1141

1142
function deserialize(s::AbstractSerializer, ::Type{Core.MethodCache})
×
1143
    name = deserialize(s)::Symbol
×
1144
    mod = deserialize(s)::Module
×
1145
    f = Base.unwrap_unionall(getglobal(mod, name))
×
1146
    return (f::Core.MethodTable).cache
×
1147
end
1148

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

1172
function deserialize(s::AbstractSerializer, ::Type{Core.LineInfoNode})
×
1173
    mod = deserialize(s)
×
1174
    if mod isa Module
×
1175
        method = deserialize(s)
×
1176
    else
1177
        # files post v1.2 and pre v1.6 are broken
1178
        method = mod
×
1179
        mod = Main
×
1180
    end
1181
    return Core.LineInfoNode(mod, method, deserialize(s)::Symbol, Int32(deserialize(s)::Union{Int32, Int}), Int32(deserialize(s)::Union{Int32, Int}))
×
1182
end
1183

1184

1185
function deserialize(s::AbstractSerializer, ::Type{PhiNode})
×
1186
    edges = deserialize(s)
×
1187
    if edges isa Vector{Any}
×
1188
        edges = Vector{Int32}(edges)
×
1189
    end
1190
    values = deserialize(s)::Vector{Any}
×
1191
    return PhiNode(edges, values)
×
1192
end
1193

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

1322
import Core: NullDebugInfo
1323

1324
if Int === Int64
1325
const OtherInt = Int32
1326
else
1327
const OtherInt = Int64
1328
end
1329

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

1379
function deserialize_fillarray!(A::Union{Array{T},Memory{T}}, s::AbstractSerializer) where {T}
8✔
1380
    for i = eachindex(A)
8✔
1381
        tag = Int32(read(s.io, UInt8)::UInt8)
365✔
1382
        if tag != UNDEFREF_TAG
365✔
1383
            @inbounds A[i] = handle_deserialize(s, tag)
365✔
1384
        end
1385
    end
725✔
1386
    return A
8✔
1387
end
1388

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

1420
function deserialize(s::AbstractSerializer, X::Type{MemoryRef{T}} where T)
×
1421
    x = Core.memoryref(deserialize(s))::X
×
1422
    i = deserialize(s)::Int
×
1423
    i == 2 || (x = Core.memoryref(x, i, true))
×
1424
    return x::X
×
1425
end
1426

1427
function deserialize(s::AbstractSerializer, X::Type{Core.AddrSpace{M}} where M)
×
1428
    Core.bitcast(X, read(s.io, UInt8))
×
1429
end
1430

1431
function deserialize_expr(s::AbstractSerializer, len)
×
1432
    e = Expr(:temp)
×
1433
    resolve_ref_immediately(s, e)
×
1434
    e.head = deserialize(s)::Symbol
×
1435
    e.args = Any[ deserialize(s) for i = 1:len ]
×
1436
    e
×
1437
end
1438

1439
module __deserialized_types__ end
1440

1441
function deserialize(s::AbstractSerializer, ::Type{Core.TypeName})
×
1442
    number = read(s.io, UInt64)
×
1443
    return deserialize_typename(s, number)
×
1444
end
1445

1446
function deserialize_typename(s::AbstractSerializer, number)
×
1447
    name = deserialize(s)::Symbol
×
1448
    tn = lookup_object_number(s, number)
×
1449
    if tn !== nothing
×
1450
        makenew = false
×
1451
    else
1452
        # reuse the same name for the type, if possible, for nicer debugging
1453
        tn_name = isdefined(__deserialized_types__, name) ? gensym() : name
×
1454
        tn = ccall(:jl_new_typename_in, Any, (Any, Any, Cint, Cint),
×
1455
                   tn_name, __deserialized_types__, false, false)
1456
        makenew = true
×
1457
    end
1458
    tn = tn::Core.TypeName
×
1459
    remember_object(s, tn, number)
×
1460
    deserialize_cycle(s, tn)
×
1461

1462
    names = deserialize(s)::SimpleVector
×
1463
    super = deserialize(s)::Type
×
1464
    parameters = deserialize(s)::SimpleVector
×
1465
    types = deserialize(s)::SimpleVector
×
1466
    attrs = Core.svec()
×
1467
    has_instance = deserialize(s)::Bool
×
1468
    abstr = deserialize(s)::Bool
×
1469
    mutabl = deserialize(s)::Bool
×
1470
    ninitialized = deserialize(s)::Int32
×
1471
    maxm = format_version(s) >= 18 ? deserialize(s)::UInt8 : UInt8(0)
×
1472

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

1494
    tag = Int32(read(s.io, UInt8)::UInt8)
×
1495
    if tag != UNDEFREF_TAG
×
1496
        mtname = handle_deserialize(s, tag)
×
1497
        defs = deserialize(s)
×
1498
        maxa = deserialize(s)::Union{Int,Int32}
×
1499
        if makenew
×
1500
            tn.singletonname = mtname
×
1501
            setfield!(tn, :max_args, Int32(maxa), :monotonic)
×
1502
        end
1503
        tag = Int32(read(s.io, UInt8)::UInt8)
×
1504
        if tag != UNDEFREF_TAG
×
1505
            kws = handle_deserialize(s, tag)
×
1506
            if makenew && !(kws isa Vector{Method})
×
1507
                # old object format -- try to forward from old to new
1508
                @eval Core.kwcall(kwargs::NamedTuple, f::$ty, args...) = $kws(kwargs, f, args...)
×
1509
            end
1510
        end
1511
    end
1512
    return tn
×
1513
end
1514

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

1555
function deserialize(s::AbstractSerializer, ::Type{UnionAll})
×
1556
    form = read(s.io, UInt8)
×
1557
    if form == 0
×
1558
        var = deserialize(s)
×
1559
        body = deserialize(s)
×
1560
        return UnionAll(var, body)
×
1561
    else
1562
        n = read(s.io, Int16)
×
1563
        t = deserialize(s)::DataType
×
1564
        w = t.name.wrapper
×
1565
        k = 0
×
1566
        while isa(w, UnionAll)
×
1567
            w = w.body
×
1568
            k += 1
×
1569
        end
×
1570
        w = t.name.wrapper
×
1571
        k -= n
×
1572
        while k > 0
×
1573
            w = w.body
×
1574
            k -= 1
×
1575
        end
×
1576
        return w
×
1577
    end
1578
end
1579

1580
function deserialize(s::AbstractSerializer, ::Type{Task})
×
1581
    t = Task(()->nothing)
×
1582
    deserialize_cycle(s, t)
×
1583
    t.code = deserialize(s)
×
1584
    t.storage = deserialize(s)
×
1585
    state = deserialize(s)
×
1586
    if state === :runnable
×
1587
        @atomic :release t._state = Base.task_state_runnable
×
1588
    elseif state === :done
×
1589
        @atomic :release t._state = Base.task_state_done
×
1590
    elseif state === :failed
×
1591
        @atomic :release t._state = Base.task_state_failed
×
1592
    else
1593
        @assert false
×
1594
    end
1595
    t.result = deserialize(s)
×
1596
    exc = deserialize(s)
×
1597
    if exc === nothing
×
1598
        t._isexception = false
×
1599
    elseif exc isa Bool
×
1600
        t._isexception = exc
×
1601
    else
1602
        t._isexception = true
×
1603
        t.result = exc
×
1604
    end
1605
    t
×
1606
end
1607

1608
function deserialize_string(s::AbstractSerializer, len::Int)
1609
    out = ccall(:jl_alloc_string, Ref{String}, (Csize_t,), len)
3,736✔
1610
    unsafe_read(s.io, pointer(out), len)
3,736✔
1611
    return out
3,736✔
1612
end
1613

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

1647
function deserialize_dict(s::AbstractSerializer, T::Type{<:AbstractDict})
502✔
1648
    n = read(s.io, Int32)
502✔
1649
    t = T(); sizehint!(t, n)
1,004✔
1650
    deserialize_cycle(s, t)
502✔
1651
    for i = 1:n
502✔
1652
        k = deserialize(s)
3,515✔
1653
        v = deserialize(s)
3,515✔
1654
        t[k] = v
3,515✔
1655
    end
6,528✔
1656
    return t
502✔
1657
end
1658

1659
function deserialize(s::AbstractSerializer, T::Type{Dict{K,V}}) where {K,V}
502✔
1660
    return deserialize_dict(s, T)
502✔
1661
end
1662

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

1665
function deserialize(s::AbstractSerializer, t::Type{Regex})
×
1666
    pattern = deserialize(s)
×
1667
    compile_options = deserialize(s)
×
1668
    match_options = deserialize(s)
×
1669
    return Regex(pattern, compile_options, match_options)
×
1670
end
1671

1672
## StackTraces
1673

1674
# provide a custom serializer that skips attempting to serialize the `outer_linfo`
1675
# which is likely to contain complex references, types, and module references
1676
# that may not exist on the receiver end
1677
function serialize(s::AbstractSerializer, frame::Base.StackTraces.StackFrame)
×
1678
    serialize_type(s, typeof(frame))
×
1679
    serialize(s, frame.func)
×
1680
    serialize(s, frame.file)
×
1681
    write(s.io, frame.line)
×
1682
    write(s.io, frame.from_c)
×
1683
    write(s.io, frame.inlined)
×
1684
    write(s.io, frame.pointer)
×
1685
    nothing
×
1686
end
1687

1688
function deserialize(s::AbstractSerializer, ::Type{Base.StackTraces.StackFrame})
×
1689
    func = deserialize(s)
×
1690
    file = deserialize(s)
×
1691
    line = read(s.io, Int)
×
1692
    from_c = read(s.io, Bool)
×
1693
    inlined = read(s.io, Bool)
×
1694
    pointer = read(s.io, UInt64)
×
1695
    return Base.StackTraces.StackFrame(func, file, line, nothing, from_c, inlined, pointer)
×
1696
end
1697

1698
function serialize(s::AbstractSerializer, lock::Base.AbstractLock)
×
1699
    # assert_havelock(lock)
1700
    serialize_cycle_header(s, lock)
×
1701
    nothing
×
1702
end
1703

1704
function deserialize(s::AbstractSerializer, ::Type{T}) where T<:Base.AbstractLock
×
1705
    lock = T()
×
1706
    deserialize_cycle(s, lock)
×
1707
    return lock
×
1708
end
1709

1710
function serialize(s::AbstractSerializer, cond::Base.GenericCondition)
×
1711
    serialize_cycle_header(s, cond) && return
×
1712
    serialize(s, cond.lock)
×
1713
    nothing
×
1714
end
1715

1716
function deserialize(s::AbstractSerializer, ::Type{T}) where T<:Base.GenericCondition
×
1717
    lock = deserialize(s)
×
1718
    cond = T(lock)
×
1719
    deserialize_cycle(s, cond)
×
1720
    return cond
×
1721
end
1722

1723
serialize(s::AbstractSerializer, l::LazyString) =
×
1724
    invoke(serialize, Tuple{AbstractSerializer,Any}, s, Base._LazyString((), string(l)))
1725

1726
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