Skip to content

Commit

Permalink
correct a misuse of line=0 handling
Browse files Browse the repository at this point in the history
  • Loading branch information
vtjnash committed Feb 23, 2024
1 parent 39e02f3 commit eaa980b
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 77 deletions.
53 changes: 26 additions & 27 deletions base/compiler/ssair/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -360,36 +360,35 @@ end

# utility function for converting a debuginfo object a particular pc to list of LineInfoNodes representing the inlining info at that pc for function `def`
# which is either `nothing` (macro-expand), a module (top-level), a Method (unspecialized code) or a MethodInstance (specialized code)
function buildLineInfoNode(debuginfo, @nospecialize(def), pc::Int)
DI = LineInfoNode[]
pc == 0 && return DI
let codeloc = getdebugidx(debuginfo, pc)
# Returns `false` if the line info should not be updated with this info because this
# statement has no effect on the line numbers. The `scopes` will still be populated however
# with as much information as was available about the inlining at that statement.
function append_scopes!(scopes::Vector{LineInfoNode}, pc::Int, debuginfo, @nospecialize(def))
doupdate = true
while true
debuginfo.def isa Symbol || (def = debuginfo.def)
codeloc = getdebugidx(debuginfo, pc)
line::Int = codeloc[1]
line < 0 && return DI # broken or disabled debug info?
if line == 0 && codeloc[2] == 0
return DI # no update
end
end
function append_scopes!(scopes::Vector{LineInfoNode}, pc::Int, debuginfo, @nospecialize(def))
while true
debuginfo.def isa Symbol || (def = debuginfo.def)
codeloc = getdebugidx(debuginfo, pc)
line::Int = codeloc[1]
line < 0 && return # broken or disabled debug info?
if debuginfo.linetable === nothing || line == 0
push!(scopes, LineInfoNode(def, debuginfo_file1(debuginfo), Int32(line)))
else
append_scopes!(scopes, line, debuginfo.linetable::Core.DebugInfo, def)
end
def = :var"macro expansion"
inl_to::Int = codeloc[2]
inl_to == 0 && break
debuginfo = debuginfo.edges[inl_to]
pc::Int = codeloc[3]
pc == 0 && break # TODO: use toplevel line?
inl_to::Int = codeloc[2]
if debuginfo.linetable === nothing || pc <= 0 || line < 0
line < 0 && (line = 0) # broken debug info
doupdate &= line != 0 || inl_to != 0 # disabled debug info--no update
push!(scopes, LineInfoNode(def, debuginfo_file1(debuginfo), Int32(line)))
else
doupdate = append_scopes!(scopes, line, debuginfo.linetable::Core.DebugInfo, def) && doupdate
end
inl_to == 0 && return doupdate
def = :var"macro expansion"
debuginfo = debuginfo.edges[inl_to]
pc::Int = codeloc[3]
end
append_scopes!(DI, pc, debuginfo, def)
end

# utility wrapper around `append_scopes!` that returns an empty list instead of false
# when there is no applicable line update
function buildLineInfoNode(debuginfo, @nospecialize(def), pc::Int)
DI = LineInfoNode[]
append_scopes!(DI, pc, debuginfo, def) || empty!(DI)
return DI
end

Expand Down
48 changes: 19 additions & 29 deletions base/stacktraces.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module StackTraces

import Base: hash, ==, show
import Core: CodeInfo, MethodInstance
using Base.IRShow: debuginfo_file1, normalize_method_name # or import buildLineInfoNode?
using Base.IRShow: normalize_method_name, append_scopes!, LineInfoNode

export StackTrace, StackFrame, stacktrace

Expand All @@ -21,10 +21,10 @@ Stack information representing execution context, with the following fields:
The name of the function containing the execution context.
- `linfo::Union{Core.MethodInstance, Method, Module, Core.CodeInfo, Nothing}`
- `linfo::Union{Method, Core.MethodInstance, Core.CodeInfo, Nothing}`
The MethodInstance or CodeInfo containing the execution context (if it could be found), \
or Module (for macro expansions)"
The Method, MethodInstance, or CodeInfo containing the execution context (if it could be found), \
or nothing (for example, if the inlining was a result of macro expansion).
- `file::Symbol`
Expand Down Expand Up @@ -55,8 +55,8 @@ struct StackFrame # this type should be kept platform-agnostic so that profiles
"the line number in the file containing the execution context"
line::Int
"the MethodInstance or CodeInfo containing the execution context (if it could be found), \
or Module (for macro expansions)"
linfo::Union{MethodInstance, Method, Module, CodeInfo, Nothing}
or nothing (for example, if the inlining was a result of macro expansion)."
linfo::Union{MethodInstance, Method, CodeInfo, Nothing}
"true if the code is from C"
from_c::Bool
"true if the code is from an inlined frame"
Expand Down Expand Up @@ -141,35 +141,25 @@ function lookup(ip::Union{Base.InterpreterIP,Core.Compiler.InterpreterIP})
file = empty_sym
line = Int32(0)
end
def = (code isa MethodInstance ? code : StackTraces) # Module just used as a token for top-level code
pc::Int = max(ip.stmt + 1, 0) # n.b. ip.stmt is 0-indexed
debuginfo = codeinfo.debuginfo
codeloc = @ccall jl_uncompress1_codeloc(debuginfo.codelocs::Any, pc::Int)::NTuple{3,Int32}
if (codeloc[1] == 0 && codeloc[2] == 0) || codeloc[1] < 0
scopes = LineInfoNode[]
append_scopes!(scopes, pc, codeinfo.debuginfo, def)
if isempty(scopes)
return [StackFrame(func, file, line, code, false, false, 0)]
end
scopes = StackFrame[]
inlined = false
def = (code isa MethodInstance ? code : StackTraces) # Module just used as a token
function append_scopes!(scopes::Vector{StackFrame}, pc::Int, debuginfo::Core.DebugInfo, @nospecialize(def), inlined::Bool)
while true
debuginfo.def isa Symbol || (def = debuginfo.def)
codeloc = @ccall jl_uncompress1_codeloc(debuginfo.codelocs::Any, pc::Int)::NTuple{3,Int32}
line = codeloc[1]
if debuginfo.linetable === nothing || pc <= 0 || line < 0
line < 0 && (line = 0) # broken debug info?
push!(scopes, StackFrame(normalize_method_name(def), debuginfo_file1(debuginfo), line, inlined ? nothing : code, false, inlined, 0))
else
append_scopes!(scopes, line - 1, debuginfo.linetable::Core.DebugInfo, def, inlined)
end
inlined = true
def = :var"macro expansion"
inl_to::Int = codeloc[2]
inl_to == 0 && break
debuginfo = debuginfo.edges[inl_to]
pc::Int = codeloc[3]
scopes = map(scopes) do lno
if inlined
def = lno.method
def isa Union{Method,MethodInstance} || (def = nothing)
else
def = codeinfo
end
sf = StackFrame(normalize_method_name(lno.method), lno.file, lno.line, def, false, inlined, 0)
inlined = true
return sf
end
append_scopes!(scopes, pc, debuginfo, def, false)
return scopes
end

Expand Down
7 changes: 4 additions & 3 deletions doc/src/devdocs/ast.md
Original file line number Diff line number Diff line change
Expand Up @@ -811,9 +811,10 @@ end

A vector of indices, with 3 values for each statement in the IR plus one for the
starting point of the block, that describe the stacktrace from that point:
1. the integer index into the `linetable.codelocs` field, giving the original location
associated with each statement (including its edges), or zero indicating to use
`linetable.firstline` as the line number.
1. the integer index into the `linetable.codelocs` field, giving the
original location associated with each statement (including its syntatic edges),
or zero indicating no change to the line number from the previously
executed statement (which is not necessarily syntatic or lexical prior).
or
the line number itself if the `linetable` field is `nothing`
2. the integer index into edges, giving the DebugInfo inlined there (or zero if there
Expand Down
34 changes: 18 additions & 16 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8674,26 +8674,23 @@ static jl_llvm_functions_t
SmallVector<DebugLineTable, 0> prev_lineinfo, new_lineinfo;
new_lineinfo.push_back(topinfo);
auto update_lineinfo = [&] (size_t pc) {
jl_debuginfo_t *debuginfo = src->debuginfo;
struct jl_codeloc_t lineidx = jl_uncompress1_codeloc(debuginfo->codelocs, pc + 1);
if (lineidx.line == 0 && lineidx.to == 0)
return false; // do not change anything
prev_lineinfo.resize(0);
std::swap(prev_lineinfo, new_lineinfo);
std::function<void(jl_debuginfo_t*, jl_value_t*, size_t, size_t)> append_lineinfo =
[&] (jl_debuginfo_t *debuginfo, jl_value_t *func, size_t to, size_t pc) -> void {
std::function<bool(jl_debuginfo_t*, jl_value_t*, size_t, size_t)> append_lineinfo =
[&] (jl_debuginfo_t *debuginfo, jl_value_t *func, size_t to, size_t pc) -> bool {
while (1) {
if (!jl_is_symbol(debuginfo->def)) // this is a path
func = debuginfo->def; // this is inlined
struct jl_codeloc_t lineidx = jl_uncompress1_codeloc(debuginfo->codelocs, pc);
size_t i = lineidx.line;
if (pc > 0 && i >= 0 && (jl_value_t*)debuginfo->linetable != jl_nothing) {
// indirection node
append_lineinfo(debuginfo->linetable, func, to, i);
if (!append_lineinfo(debuginfo->linetable, func, to, i))
return false; // no update
}
else {
if (i < 0)
i = 0; // pc out of range: broken debuginfo?
if (i < 0) // pc out of range: broken debuginfo?
return false;
if (i == 0 && lineidx.to == 0) // no update
return false;
// actual node
DebugLineTable info;
info.edgeid = to;
Expand Down Expand Up @@ -8739,15 +8736,20 @@ static jl_llvm_functions_t
}
to = lineidx.to;
if (to == 0)
break;
return true;
pc = lineidx.pc;
debuginfo = (jl_debuginfo_t*)jl_svecref(debuginfo->edges, to - 1);
func = NULL;
}
};
append_lineinfo(debuginfo, (jl_value_t*)lam, 0, pc + 1);
assert(new_lineinfo.size() > 0);
return true;
prev_lineinfo.resize(0);
std::swap(prev_lineinfo, new_lineinfo);
bool updated = append_lineinfo(src->debuginfo, (jl_value_t*)lam, 0, pc + 1);
if (!updated)
std::swap(prev_lineinfo, new_lineinfo);
else
assert(new_lineinfo.size() > 0);
return updated;
};

SmallVector<MDNode*, 0> aliasscopes;
Expand Down Expand Up @@ -8903,7 +8905,7 @@ static jl_llvm_functions_t
bool is_tracked = in_tracked_path(file);
if (do_coverage(is_user_code, is_tracked)) {
for (size_t pc = 0; 1; pc++) {
struct jl_codeloc_t lineidx = jl_uncompress1_codeloc(debuginfo->codelocs, pc + 1);
struct jl_codeloc_t lineidx = jl_uncompress1_codeloc(debuginfo->codelocs, pc);
if (lineidx.line == -1)
break;
jl_debuginfo_t *linetable = debuginfo->linetable;
Expand Down
4 changes: 2 additions & 2 deletions src/stackwalk.c
Original file line number Diff line number Diff line change
Expand Up @@ -718,8 +718,8 @@ static void jl_print_debugloc(jl_debuginfo_t *debuginfo, jl_value_t *func, size_
jl_print_debugloc(debuginfo->linetable, func, ip2, 0);
}
else {
if (ip2 < 0)
ip2 = 0; // broken debug info?
if (ip2 < 0) // set broken debug info to ignored
ip2 = 0;
const char *func_name = jl_debuginfo_name(func);
const char *file = jl_debuginfo_file(debuginfo);
jl_safe_print_codeloc(func_name, file, ip2, inlined);
Expand Down

0 comments on commit eaa980b

Please sign in to comment.