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

JuliaLang / julia / 1554

08 Jan 2026 06:52PM UTC coverage: 76.664% (+0.04%) from 76.623%
1554

push

buildkite

web-flow
[JuliaLowering] Fix-up always-defined check in `is_valid_body_ir_argument` (#60602)

This was slightly mis-translated from the flisp side:
```scheme
    (define (valid-body-ir-argument? aval)
      (or (valid-ir-argument? aval)
          (and (symbol? aval) ; Arguments are always defined slots
               (or (memq aval (lam:args lam))
                   (let ((vi (get vinfo-table aval #f)))
                     (and vi (vinfo:never-undef vi)))))))
```

Noticed in
https://github.com/JuliaLang/julia/pull/60567#discussion_r2672556146

62618 of 81679 relevant lines covered (76.66%)

23088815.22 hits per line

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

79.04
/base/stacktraces.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
"""
4
Tools for collecting and manipulating stack traces. Mainly used for building errors.
5
"""
6
module StackTraces
7

8

9
import Base: hash, ==, show
10

11
using Core: CodeInfo, MethodInstance, CodeInstance
12
using Base.IRShow
13

14
export StackTrace, StackFrame, stacktrace
15

16
"""
17
    StackFrame
18

19
Stack information representing execution context, with the following fields:
20

21
- `func::Symbol`
22

23
  The name of the function containing the execution context.
24

25
- `linfo::Union{Method, Core.MethodInstance, Core.CodeInstance, Core.CodeInfo, Nothing}`
26

27
  The Method, MethodInstance, CodeInstance, or CodeInfo containing the execution context (if it could be found),
28
     or nothing (for example, if the inlining was a result of macro expansion).
29

30
- `file::Symbol`
31

32
  The path to the file containing the execution context.
33

34
- `line::Int`
35

36
  The line number in the file containing the execution context.
37

38
- `from_c::Bool`
39

40
  True if the code is from C.
41

42
- `inlined::Bool`
43

44
  True if the code is from an inlined frame.
45

46
- `pointer::UInt64`
47

48
  Representation of the pointer to the execution context as returned by `backtrace`.
49

50
"""
51
struct StackFrame # this type should be kept platform-agnostic so that profiles can be dumped on one machine and read on another
52
    "the name of the function containing the execution context"
24,015✔
53
    func::Symbol
54
    "the path to the file containing the execution context"
55
    file::Symbol
56
    "the line number in the file containing the execution context"
57
    line::Int
58
    "the CodeInstance or CodeInfo containing the execution context (if it could be found), \
59
     or nothing (for example, if the inlining was a result of macro expansion)."
60
    linfo::Union{Core.MethodInstance, Core.CodeInstance, Method, CodeInfo, Nothing}
61
    "true if the code is from C"
62
    from_c::Bool
63
    "true if the code is from an inlined frame"
64
    inlined::Bool
65
    "representation of the pointer to the execution context as returned by `backtrace`"
66
    pointer::UInt64  # Large enough to be read losslessly on 32- and 64-bit machines.
67
end
68

69
StackFrame(func, file, line) = StackFrame(Symbol(func), Symbol(file), line,
24✔
70
                                          nothing, false, false, 0)
71

72
"""
73
    StackTrace
74

75
An alias for `Vector{StackFrame}` provided for convenience; returned by calls to
76
`stacktrace`.
77
"""
78
const StackTrace = Vector{StackFrame}
79

80
const empty_sym = Symbol("")
81
const UNKNOWN = StackFrame(empty_sym, empty_sym, -1, nothing, true, false, 0) # === lookup(C_NULL)
82

83

84
#=
85
If the StackFrame has function and line information, we consider two of them the same if
86
they share the same function/line information.
87
=#
88
function ==(a::StackFrame, b::StackFrame)
89
    return a.line == b.line && a.from_c == b.from_c && a.func == b.func && a.file == b.file && a.inlined == b.inlined # excluding linfo and pointer
264,407✔
90
end
91

92
function hash(frame::StackFrame, h::UInt)
93
    h ⊻= 0xf4fbda67fe20ce88 % UInt
1,642✔
94
    h = hash(frame.line, h)
1,691,492✔
95
    h = hash(frame.file, h)
1,691,492✔
96
    h = hash(frame.func, h)
1,691,492✔
97
    h = hash(frame.from_c, h)
1,691,492✔
98
    h = hash(frame.inlined, h)
1,691,492✔
99
    return h
1,499✔
100
end
101

102
"""
103
    lookup(pointer::Ptr{Cvoid})::Vector{StackFrame}
104

105
Given a pointer to an execution context (usually generated by a call to `backtrace`), looks
106
up stack frame context information. Returns an array of frame information for all functions
107
inlined at that point, innermost function first.
108
"""
109
Base.@constprop :none function lookup(pointer::Ptr{Cvoid})
10,226✔
110
    infos = ccall(:jl_lookup_code_address, Any, (Ptr{Cvoid}, Cint), pointer, false)::Core.SimpleVector
10,226✔
111
    pointer = convert(UInt64, pointer)
10,226✔
112
    isempty(infos) && return [StackFrame(empty_sym, empty_sym, -1, nothing, true, false, pointer)] # this is equal to UNKNOWN
10,226✔
113
    res = Vector{StackFrame}(undef, length(infos))
10,226✔
114
    for i in 1:length(infos)
20,130✔
115
        info = infos[i]::Core.SimpleVector
13,402✔
116
        @assert length(info) == 6 "corrupt return from jl_lookup_code_address"
13,402✔
117
        func = info[1]::Symbol
13,402✔
118
        file = info[2]::Symbol
13,402✔
119
        linenum = info[3]::Int
13,402✔
120
        linfo = info[4]
13,402✔
121
        res[i] = StackFrame(func, file, linenum, linfo, info[5]::Bool, info[6]::Bool, pointer)
13,402✔
122
    end
16,578✔
123
    return res
10,226✔
124
end
125

126
const top_level_scope_sym = Symbol("top-level scope")
127

128
function lookup(ip::Base.InterpreterIP)
439✔
129
    code = ip.code
439✔
130
    if code === nothing
439✔
131
        # interpreted top-level expression with no CodeInfo
132
        return [StackFrame(top_level_scope_sym, empty_sym, 0, nothing, false, false, 0)]
×
133
    end
134
    # prepare approximate code info
135
    if code isa MethodInstance && (meth = code.def; meth isa Method)
439✔
136
        func = meth.name
×
137
        file = meth.file
×
138
        line = meth.line
×
139
        codeinfo = meth.source
×
140
    else
141
        func = top_level_scope_sym
439✔
142
        file = empty_sym
439✔
143
        line = Int32(0)
439✔
144
        if code isa Core.CodeInstance
439✔
145
            codeinfo = code.inferred::CodeInfo
×
146
            def = code.def
×
147
            if isa(def, Core.ABIOverride)
×
148
                def = def.def
×
149
            end
150
            if isa(def, MethodInstance)
×
151
                let meth = def.def
×
152
                    if isa(meth, Method)
×
153
                        func = meth.name
×
154
                        file = meth.file
×
155
                        line = meth.line
×
156
                    end
157
                end
158
            end
159
        else
160
            codeinfo = code::CodeInfo
439✔
161
        end
162
    end
163
    def = (code isa CodeInfo ? StackTraces : code) # Module just used as a token for top-level code
439✔
164
    pc::Int = max(ip.stmt + 1, 0) # n.b. ip.stmt is 0-indexed
439✔
165
    scopes = IRShow.LineInfoNode[]
439✔
166
    IRShow.append_scopes!(scopes, pc, codeinfo.debuginfo, def)
878✔
167
    if isempty(scopes)
439✔
168
        return [StackFrame(func, file, line, code, false, false, 0)]
×
169
    end
170
    res = Vector{StackFrame}(undef, length(scopes))
439✔
171
    inlined = false
439✔
172
    def_local = def
439✔
173
    for i in eachindex(scopes)
867✔
174
        lno = scopes[i]
1,515✔
175
        if inlined
1,515✔
176
            def_local = lno.method
1,076✔
177
            def_local isa Union{Method,Core.CodeInstance,MethodInstance} || (def_local = nothing)
1,076✔
178
        else
179
            def_local = codeinfo
439✔
180
        end
181
        res[i] = StackFrame(IRShow.normalize_method_name(lno.method), lno.file, lno.line,
1,515✔
182
            def_local, false, inlined, 0)
183
        inlined = true
1,515✔
184
    end
2,591✔
185
    return res
439✔
186
end
187

188
"""
189
    stacktrace([trace::Vector{Ptr{Cvoid}},] [c_funcs::Bool=false])::StackTrace
190

191
Return a stack trace in the form of a vector of `StackFrame`s. (By default stacktrace
192
doesn't return C functions, but this can be enabled.) When called without specifying a
193
trace, `stacktrace` first calls `backtrace`.
194
"""
195
Base.@constprop :none function stacktrace(trace::Vector{<:Union{Base.InterpreterIP,Ptr{Cvoid}}}, c_funcs::Bool=false)
335✔
196
    stack = StackTrace()
2,024✔
197
    for ip in trace
266✔
198
        for frame in lookup(ip)
3,930✔
199
            # Skip frames that come from C calls.
200
            if c_funcs || !frame.from_c
10,149✔
201
                push!(stack, frame)
2,258✔
202
            end
203
        end
5,231✔
204
    end
3,930✔
205
    return stack
266✔
206
end
207

208
Base.@constprop :none function stacktrace(c_funcs::Bool=false)
209
    stack = stacktrace(backtrace(), c_funcs)
12✔
210
    # Remove frame for this function (and any functions called by this function).
211
    remove_frames!(stack, :stacktrace)
212
    # also remove all of the non-Julia functions that led up to this point (if that list is non-empty)
213
    c_funcs && deleteat!(stack, 1:(something(findfirst(frame -> !frame.from_c, stack), 1) - 1))
214
    return stack
215
end
216

217
"""
218
    remove_frames!(stack::StackTrace, name::Symbol)
219

220
Takes a `StackTrace` (a vector of `StackFrames`) and a function name (a `Symbol`) and
221
removes the `StackFrame` specified by the function name from the `StackTrace` (also removing
222
all frames above the specified function). Primarily used to remove `StackTraces` functions
223
from the `StackTrace` prior to returning it.
224
"""
225
function remove_frames!(stack::StackTrace, name::Symbol)
×
226
    deleteat!(stack, 1:something(findlast(frame -> frame.func == name, stack), 0))
×
227
    return stack
×
228
end
229

230
function remove_frames!(stack::StackTrace, names::Vector{Symbol})
×
231
    deleteat!(stack, 1:something(findlast(frame -> frame.func in names, stack), 0))
×
232
    return stack
×
233
end
234

235
"""
236
    remove_frames!(stack::StackTrace, m::Module)
237

238
Return the `StackTrace` with all `StackFrame`s from the provided `Module` removed.
239
"""
240
function remove_frames!(stack::StackTrace, m::Module)
241
    filter!(f -> !from(f, m), stack)
2✔
242
    return stack
×
243
end
244

245
is_top_level_frame(f::StackFrame) = f.linfo isa CodeInfo || (f.linfo === nothing && f.func === top_level_scope_sym)
×
246

247
function frame_method_or_module(lkup::StackFrame)
248
    code = lkup.linfo
3,006✔
249
    code isa Method && return code
3,006✔
250
    code isa Module && return code
1,097✔
251
    mi = frame_mi(lkup)
3,018✔
252
    mi isa MethodInstance || return nothing
3,020✔
253
    return mi.def
2,992✔
254
end
255

256
function frame_mi(lkup::StackFrame)
257
    code = lkup.linfo
5,993✔
258
    code isa Core.CodeInstance && (code = code.def)
5,993✔
259
    code isa Core.ABIOverride && (code = code.def)
5,993✔
260
    code isa MethodInstance || return nothing
6,007✔
261
    return code
5,979✔
262
end
263

264
function show_spec_linfo(io::IO, frame::StackFrame)
5,770✔
265
    linfo = frame.linfo
5,770✔
266
    if linfo === nothing
5,770✔
267
        if frame.func === empty_sym
2,441✔
268
            print(io, "ip:0x", string(frame.pointer, base=16))
1✔
269
        elseif frame.func === top_level_scope_sym
2,440✔
270
            print(io, "top-level scope")
70✔
271
        else
272
            Base.print_within_stacktrace(io, Base.demangle_function_name(string(frame.func)), bold=true)
2,370✔
273
        end
274
    elseif linfo isa CodeInfo
3,329✔
275
        print(io, "top-level scope")
339✔
276
    elseif linfo isa Module
2,990✔
277
        Base.print_within_stacktrace(io, Base.demangle_function_name(string(frame.func)), bold=true)
×
278
    else
279
        if linfo isa Union{MethodInstance, CodeInstance}
2,990✔
280
            def = frame_method_or_module(frame)
5,980✔
281
            if def isa Module
2,990✔
282
                Base.show_mi(io, linfo::MethodInstance, #=from_stackframe=#true)
×
283
            elseif linfo isa CodeInstance && linfo.owner !== nothing
2,990✔
284
                show_custom_spec_sig(io, linfo.owner, linfo, frame)
3✔
285
            else
286
                # Equivalent to the default implementation of `show_custom_spec_sig`
287
                # for `linfo isa CodeInstance`, but saves an extra dynamic dispatch.
288
                show_spec_sig(io, def, frame_mi(frame).specTypes)
2,987✔
289
            end
290
        else
291
            m = linfo::Method
×
292
            show_spec_sig(io, m, m.sig)
×
293
        end
294
    end
295
end
296

297
# Can be extended by compiler packages to customize backtrace display of custom code instance frames
298
function show_custom_spec_sig(io::IO, @nospecialize(owner), linfo::CodeInstance, frame::StackFrame)
299
    mi = Base.get_ci_mi(linfo)
6✔
300
    return show_spec_sig(io, mi.def, mi.specTypes)
3✔
301
end
302

303
function show_spec_sig(io::IO, m::Method, @nospecialize(sig::Type))
2,990✔
304
    if get(io, :limit, :false)::Bool
8,989✔
305
        if !haskey(io, :displaysize)
2,543✔
306
            io = IOContext(io, :displaysize => displaysize(io))
323✔
307
        end
308
    end
309
    argnames = Base.method_argnames(m)
5,980✔
310
    argnames = replace(argnames, :var"#unused#" => :var"")
2,990✔
311
    if m.nkw > 0
2,990✔
312
        # rearrange call kw_impl(kw_args..., func, pos_args...) to func(pos_args...; kw_args)
313
        kwarg_types = Any[ fieldtype(sig, i) for i = 2:(1+m.nkw) ]
439✔
314
        uw = Base.unwrap_unionall(sig)::DataType
343✔
315
        pos_sig = Base.rewrap_unionall(Tuple{uw.parameters[(m.nkw+2):end]...}, sig)
343✔
316
        kwnames = argnames[2:(m.nkw+1)]
686✔
317
        for i = 1:length(kwnames)
398✔
318
            str = string(kwnames[i])::String
439✔
319
            if endswith(str, "...")
439✔
320
                kwnames[i] = Symbol(str[1:end-3])
×
321
            end
322
        end
535✔
323
        Base.show_tuple_as_call(io, m.name, pos_sig;
343✔
324
                                demangle=true,
325
                                kwargs=zip(kwnames, kwarg_types),
326
                                argnames=argnames[m.nkw+2:end])
327
    else
328
        Base.show_tuple_as_call(io, m.name, sig; demangle=true, argnames)
2,647✔
329
    end
330
end
331

332
function show(io::IO, frame::StackFrame)
402✔
333
    show_spec_linfo(io, frame)
402✔
334
    if frame.file !== empty_sym
402✔
335
        file_info = basename(string(frame.file))
389✔
336
        print(io, " at ")
389✔
337
        print(io, file_info, ":")
389✔
338
        if frame.line >= 0
389✔
339
            print(io, frame.line)
380✔
340
        else
341
            print(io, "?")
9✔
342
        end
343
    end
344
    if frame.inlined
402✔
345
        print(io, " [inlined]")
111✔
346
    end
347
end
348

349
function Base.parentmodule(frame::StackFrame)
350
    linfo = frame.linfo
11,156✔
351
    if linfo isa CodeInstance
11,156✔
352
        linfo = linfo.def
4,060✔
353
        if isa(linfo, Core.ABIOverride)
4,060✔
354
            linfo = linfo.def
×
355
        end
356
    end
357
    if linfo isa MethodInstance
11,156✔
358
        def = linfo.def
5,338✔
359
        if def isa Module
5,338✔
360
            return def
×
361
        else
362
            return (def::Method).module
5,338✔
363
        end
364
    elseif linfo isa Method
5,818✔
365
        return linfo.module
×
366
    elseif linfo isa Module
5,818✔
367
        return linfo
×
368
    else
369
        # The module is not always available (common reasons include
370
        # frames arising from the interpreter)
371
        nothing
2,223✔
372
    end
373
end
374

375
"""
376
    from(frame::StackFrame, filter_mod::Module)::Bool
377

378
Return whether the `frame` is from the provided `Module`
379
"""
380
function from(frame::StackFrame, m::Module)
×
381
    return parentmodule(frame) === m
×
382
end
383

384
end  # module StackTraces
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