Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert inlined method signature stacktrace lookup code #52754

Merged
merged 2 commits into from
Jan 14, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 2 additions & 97 deletions base/stacktraces.jl
Original file line number Diff line number Diff line change
Expand Up @@ -97,87 +97,6 @@ function hash(frame::StackFrame, h::UInt)
return h
end

get_inlinetable(::Any) = nothing
function get_inlinetable(mi::MethodInstance)
isdefined(mi, :def) && mi.def isa Method && isdefined(mi, :cache) && isdefined(mi.cache, :inferred) &&
mi.cache.inferred !== nothing || return nothing
linetable = ccall(:jl_uncompress_ir, Any, (Any, Any, Any), mi.def, mi.cache, mi.cache.inferred).linetable
return filter!(x -> x.inlined_at > 0, linetable)
end

get_method_instance_roots(::Any) = nothing
function get_method_instance_roots(mi::Union{Method, MethodInstance})
m = mi isa MethodInstance ? mi.def : mi
m isa Method && isdefined(m, :roots) || return nothing
return filter(x -> x isa MethodInstance, m.roots)
end

function lookup_inline_frame_info(func::Symbol, file::Symbol, linenum::Int, inlinetable::Vector{Core.LineInfoNode})
#REPL frames and some base files lack this prefix while others have it; should fix?
filestripped = Symbol(lstrip(string(file), ('.', '\\', '/')))
linfo = nothing
#=
Some matching entries contain the MethodInstance directly.
Other matching entries contain only a Method or Symbol (function name); such entries
are located after the entry with the MethodInstance, so backtracking is required.
If backtracking fails, the Method or Module is stored for return, but we continue
the search in case a MethodInstance is found later.
TODO: If a backtrack has failed, do we need to backtrack again later if another Method
or Symbol match is found? Or can a limit on the subsequent backtracks be placed?
=#
for (i, line) in enumerate(inlinetable)
Base.IRShow.method_name(line) === func && line.file ∈ (file, filestripped) && line.line == linenum || continue
if line.method isa MethodInstance
linfo = line.method
break
elseif line.method isa Method || line.method isa Symbol
linfo = line.method isa Method ? line.method : line.module
# backtrack to find the matching MethodInstance, if possible
for j in (i - 1):-1:1
nextline = inlinetable[j]
nextline.inlined_at == line.inlined_at && Base.IRShow.method_name(line) === Base.IRShow.method_name(nextline) && line.file === nextline.file || break
if nextline.method isa MethodInstance
linfo = nextline.method
break
end
end
end
end
return linfo
end

function lookup_inline_frame_info(func::Symbol, file::Symbol, miroots::Vector{Any})
# REPL frames and some base files lack this prefix while others have it; should fix?
filestripped = Symbol(lstrip(string(file), ('.', '\\', '/')))
matches = filter(miroots) do x
x.def isa Method || return false
m = x.def::Method
return m.name == func && m.file ∈ (file, filestripped)
end
if length(matches) > 1
# ambiguous, check if method is same and return that instead
all_matched = true
for m in matches
all_matched = m.def.line == matches[1].def.line &&
m.def.module == matches[1].def.module
all_matched || break
end
if all_matched
return matches[1].def
end
# all else fails, return module if they match, or give up
all_matched = true
for m in matches
all_matched = m.def.module == matches[1].def.module
all_matched || break
end
return all_matched ? matches[1].def.module : nothing
elseif length(matches) == 1
return matches[1]
end
return nothing
end

"""
lookup(pointer::Ptr{Cvoid}) -> Vector{StackFrame}

Expand All @@ -189,25 +108,11 @@ Base.@constprop :none function lookup(pointer::Ptr{Cvoid})
infos = ccall(:jl_lookup_code_address, Any, (Ptr{Cvoid}, Cint), pointer, false)::Core.SimpleVector
pointer = convert(UInt64, pointer)
isempty(infos) && return [StackFrame(empty_sym, empty_sym, -1, nothing, true, false, pointer)] # this is equal to UNKNOWN
parent_linfo = infos[end][4]
inlinetable = get_inlinetable(parent_linfo)
miroots = inlinetable === nothing ? get_method_instance_roots(parent_linfo) : nothing # fallback if linetable missing
res = Vector{StackFrame}(undef, length(infos))
for i in reverse(1:length(infos))
for i in 1:length(infos)
info = infos[i]::Core.SimpleVector
@assert(length(info) == 6)
func = info[1]::Symbol
file = info[2]::Symbol
linenum = info[3]::Int
linfo = info[4]
if i < length(infos)
if inlinetable !== nothing
linfo = lookup_inline_frame_info(func, file, linenum, inlinetable)
elseif miroots !== nothing
linfo = lookup_inline_frame_info(func, file, miroots)
end
end
res[i] = StackFrame(func, file, linenum, linfo, info[5]::Bool, info[6]::Bool, pointer)
res[i] = StackFrame(info[1]::Symbol, info[2]::Symbol, info[3]::Int, info[4], info[5]::Bool, info[6]::Bool, pointer)
end
return res
end
Expand Down