Skip to content

Commit

Permalink
Emit debug info for inlined code to improve line #s
Browse files Browse the repository at this point in the history
Utilizes the DebugLoc "inlinedAt" parameter to remember inlining location in
addition to source code origin. When available, we now print both the inlinee
origin below the top-level call site.

Mostly addresses #1334. (this does not handle nested inlines, which may require
deeper changes)
  • Loading branch information
ihnorton committed Aug 22, 2015
1 parent 807b3fe commit 0a91769
Show file tree
Hide file tree
Showing 21 changed files with 259 additions and 134 deletions.
3 changes: 2 additions & 1 deletion base/boot.jl
Expand Up @@ -87,6 +87,7 @@
#end

#immutable LineNumberNode
# file::Symbol
# line::Int
#end

Expand Down Expand Up @@ -284,13 +285,13 @@ TypeConstructor(p::ANY, t::ANY) = ccall(:jl_new_type_constructor, Any, (Any, Any
Expr(args::ANY...) = _expr(args...)

_new(typ::Symbol, argty::Symbol) = eval(:(Core.call(::Type{$typ}, n::$argty) = $(Expr(:new, typ, :n))))
_new(:LineNumberNode, :Int)
_new(:LabelNode, :Int)
_new(:GotoNode, :Int)
_new(:TopNode, :Symbol)
_new(:NewvarNode, :Symbol)
_new(:QuoteNode, :ANY)
_new(:GenSym, :Int)
eval(:(Core.call(::Type{LineNumberNode}, f::Symbol, l::Int) = $(Expr(:new, :LineNumberNode, :f, :l))))
eval(:(Core.call(::Type{GlobalRef}, m::Module, s::Symbol) = $(Expr(:new, :GlobalRef, :m, :s))))

Module(name::Symbol=:anonymous, std_imports::Bool=true) = ccall(:jl_f_new_module, Any, (Any, Bool), name, std_imports)::Module
Expand Down
2 changes: 1 addition & 1 deletion base/cartesian.jl
Expand Up @@ -222,7 +222,7 @@ function poplinenum(ex::Expr)
if ex.head == :block
if length(ex.args) == 1
return ex.args[1]
elseif length(ex.args) == 2 && ex.args[1].head == :line
elseif length(ex.args) == 2 && isa(ex.args[1], LineNumberNode)
return ex.args[2]
end
end
Expand Down
2 changes: 1 addition & 1 deletion base/deprecated.jl
Expand Up @@ -80,7 +80,7 @@ function firstcaller(bt::Array{Ptr{Void},1}, funcsym::Symbol)
if lkup === ()
continue
end
fname, file, line, fromC = lkup
fname, file, line, inlined_file, inlined_line, fromC = lkup
if fname == funcsym
break
end
Expand Down
2 changes: 1 addition & 1 deletion base/docs/Docs.jl
Expand Up @@ -287,7 +287,7 @@ isexpr(x, ts...) = any(T->isa(T, Type) && isa(x, T), ts)

function unblock(ex)
isexpr(ex, :block) || return ex
exs = filter(ex->!isexpr(ex, :line), ex.args)
exs = filter(ex -> !(isa(ex, LineNumberNode) || isexpr(ex, :line)), ex.args)
length(exs) == 1 || return ex
return unblock(exs[1])
end
Expand Down
2 changes: 1 addition & 1 deletion base/essentials.jl
Expand Up @@ -40,7 +40,7 @@ call(T::Type{UTF8String}, d::Array{UInt8,1}) = Core.call(T, d)
call(T::Type{TypeVar}, args...) = Core.call(T, args...)
call(T::Type{TypeConstructor}, args...) = Core.call(T, args...)
call(T::Type{Expr}, args::ANY...) = _expr(args...)
call(T::Type{LineNumberNode}, n::Int) = Core.call(T, n)
call(T::Type{LineNumberNode}, f::Symbol, n::Int) = Core.call(T, f, n)
call(T::Type{LabelNode}, n::Int) = Core.call(T, n)
call(T::Type{GotoNode}, n::Int) = Core.call(T, n)
call(T::Type{QuoteNode}, x::ANY) = Core.call(T, x)
Expand Down
8 changes: 5 additions & 3 deletions base/profile.jl
Expand Up @@ -99,11 +99,13 @@ immutable LineInfo
func::ByteString
file::ByteString
line::Int
inlined_file::ByteString
inlined_line::Int
fromC::Bool
ip::Int64 # large enough that this struct can be losslessly read on any machine (32 or 64 bit)
end

const UNKNOWN = LineInfo("?", "?", -1, true, 0)
const UNKNOWN = LineInfo("?", "?", -1, "?", -1, true, 0)

#
# If the LineInfo has function and line information, we consider two of them the same
Expand Down Expand Up @@ -134,8 +136,8 @@ maxlen_data() = convert(Int, ccall(:jl_profile_maxlen_data, Csize_t, ()))

function lookup(ip::Ptr{Void})
info = ccall(:jl_lookup_code_address, Any, (Ptr{Void},Cint), ip, false)
if length(info) == 5
return LineInfo(string(info[1]), string(info[2]), Int(info[3]), info[4], Int64(info[5]))
if length(info) == 7
return LineInfo(string(info[1]), string(info[2]), Int(info[3]), string(info[4]), Int(info[5]), info[6], Int64(info[7]))
else
return UNKNOWN
end
Expand Down
34 changes: 25 additions & 9 deletions base/replutil.jl
Expand Up @@ -104,7 +104,7 @@ function showerror(io::IO, ex::DomainError, bt; backtrace=true)
print(io, "DomainError:")
for b in bt
code = ccall(:jl_lookup_code_address, Any, (Ptr{Void}, Cint), b-1, true)
if length(code) == 5 && !code[4] # code[4] == fromC
if length(code) == 7 && !code[6] # code[6] == fromC
if code[1] in (:log, :log2, :log10, :sqrt) # TODO add :besselj, :besseli, :bessely, :besselk
println(io,"\n$(code[1]) will only return a complex result if called with a complex argument.")
print(io, "try $(code[1]) (complex(x))")
Expand Down Expand Up @@ -328,16 +328,27 @@ function show_method_candidates(io::IO, ex::MethodError)
end
end

function show_trace_entry(io, fname, file, line, n)
function show_trace_entry(io, fname, file, line, inlinedfile, inlinedline, n)
print(io, "\n")
print(io, " in ", fname, " at ", file)
print(io, " in ", fname)

if (inlinedfile != symbol(""))
print(io, " at ", inlinedfile, ":", inlinedline)
print(io, " \n [ thrown by inlined function defined at ]\n ")
else
print(io, " at ")
end

print(io, file)

if line >= 1
try
print(io, ":", line)
catch
print(io, '?') #for when dec is not yet defined
end
end

if n > 1
print(io, " (repeats ", n, " times)")
end
Expand All @@ -356,38 +367,43 @@ function show_backtrace(io::IO, t, set=1:typemax(Int))
end

function show_backtrace(io::IO, top_function::Symbol, t, set)
process_entry(lastname, lastfile, lastline, n) = show_trace_entry(io, lastname, lastfile, lastline, n)
process_entry(lastname, lastfile, lastline, last_inlinedfile, last_inlinedline, n) =
show_trace_entry(io, lastname, lastfile, lastline, last_inlinedfile, last_inlinedline, n)
process_backtrace(process_entry, top_function, t, set)
end

# process the backtrace, up to (but not including) top_function
function process_backtrace(process_func::Function, top_function::Symbol, t, set)
n = 1
lastfile = ""; lastline = -11; lastname = symbol("#")
lastfile = ""; lastline = -11; lastname = symbol("#");
last_inlinedfile = ""; last_inlinedline = -1
local fname, file, line
count = 0
for i = 1:length(t)
lkup = ccall(:jl_lookup_code_address, Any, (Ptr{Void}, Cint), t[i]-1, true)
if lkup === nothing
continue
end
fname, file, line, fromC = lkup
fname, file, line, inlinedfile, inlinedline, fromC = lkup

if fromC; continue; end
if i == 1 && fname == :error; continue; end
if fname == top_function; break; end
count += 1
if !in(count, set); continue; end

if file != lastfile || line != lastline || fname != lastname
if lastline != -11
process_func(lastname, lastfile, lastline, n)
process_func(lastname, lastfile, lastline, last_inlinedfile, last_inlinedline, n)
end
n = 1
lastfile = file; lastline = line; lastname = fname
lastfile = file; lastline = line; lastname = fname;
last_inlinedfile = inlinedfile; last_inlinedline = inlinedline;
else
n += 1
end
end
if n > 1 || lastline != -11
process_func(lastname, lastfile, lastline, n)
process_func(lastname, lastfile, lastline, last_inlinedfile, last_inlinedline, n)
end
end
10 changes: 2 additions & 8 deletions base/show.jl
Expand Up @@ -318,7 +318,6 @@ is_expr(ex, head::Symbol) = (isa(ex, Expr) && (ex.head == head))
is_expr(ex, head::Symbol, n::Int) = is_expr(ex, head) && length(ex.args) == n

is_linenumber(ex::LineNumberNode) = true
is_linenumber(ex::Expr) = is(ex.head, :line)
is_linenumber(ex) = false

is_quoted(ex) = false
Expand Down Expand Up @@ -351,8 +350,7 @@ end

emphasize(io, str::AbstractString) = have_color ? print_with_color(:red, io, str) : print(io, uppercase(str))

show_linenumber(io::IO, line) = print(io," # line ",line,':')
show_linenumber(io::IO, line, file) = print(io," # ",file,", line ",line,':')
show_linenumber(io::IO, file, line) = print(io," # ", file,", line ",line,':')

# show a block, e g if/for/etc
function show_block(io::IO, head, args::Vector, body, indent::Int)
Expand Down Expand Up @@ -421,7 +419,7 @@ end
## AST printing ##

show_unquoted(io::IO, sym::Symbol, ::Int, ::Int) = print(io, sym)
show_unquoted(io::IO, ex::LineNumberNode, ::Int, ::Int) = show_linenumber(io, ex.line)
show_unquoted(io::IO, ex::LineNumberNode, ::Int, ::Int) = show_linenumber(io, ex.file, ex.line)
show_unquoted(io::IO, ex::LabelNode, ::Int, ::Int) = print(io, ex.label, ": ")
show_unquoted(io::IO, ex::GotoNode, ::Int, ::Int) = print(io, "goto ", ex.label)
show_unquoted(io::IO, ex::TopNode, ::Int, ::Int) = print(io,"top(",ex.name,')')
Expand Down Expand Up @@ -652,10 +650,6 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int)
print(io, "typealias ")
show_list(io, args, ' ', indent)

elseif is(head, :line) && 1 <= nargs <= 2
show_type = false
show_linenumber(io, args...)

elseif is(head, :if) && nargs == 3 # if/else
show_block(io, "if", args[1], args[2], indent)
show_block(io, "else", args[3], indent)
Expand Down
3 changes: 2 additions & 1 deletion base/task.jl
Expand Up @@ -24,7 +24,8 @@ type CapturedException

# Process bt_raw so that it can be safely serialized
bt_lines = Any[]
process_func(name, file, line, n) = push!(bt_lines, (name, file, line, n))
process_func(name, file, line, inlined_file, inlined_line, n) =
push!(bt_lines, (name, file, line, inlined_file, inlined_line, n))
process_backtrace(process_func, :(:), bt_raw, 1:100) # Limiting this to 100 lines.

new(ex, bt_lines)
Expand Down
6 changes: 3 additions & 3 deletions src/alloc.c
Expand Up @@ -335,9 +335,9 @@ jl_lambda_info_t *jl_new_lambda_info(jl_value_t *ast, jl_svec_t *sparams, jl_mod
li->line = 0;
if (ast != NULL && jl_is_expr(ast)) {
jl_value_t *body1 = skip_meta(jl_lam_body((jl_expr_t*)ast)->args);
if (jl_is_expr(body1) && ((jl_expr_t*)body1)->head == line_sym) {
li->file = (jl_sym_t*)jl_exprarg(body1, 1);
li->line = jl_unbox_long(jl_exprarg(body1, 0));
if (jl_is_linenode(body1)) {
li->file = (jl_sym_t*)jl_fieldref(body1, 0);
li->line = jl_unbox_long(jl_fieldref(body1, 1));
}
}
li->module = ctx;
Expand Down
21 changes: 16 additions & 5 deletions src/ast.c
Expand Up @@ -326,9 +326,14 @@ static jl_value_t *scm_to_julia_(value_t e, int eo)

e = cdr_(e);
if (!eo) {
if (sym == line_sym && n==1) {
return jl_new_struct(jl_linenumbernode_type,
scm_to_julia_(car_(e),0));
if (sym == line_sym && n==2) {
jl_value_t *filename = scm_to_julia_(car_(cdr_(e)),0);
jl_value_t *linenum = scm_to_julia_(car_(e),0);
JL_GC_PUSH2(&filename, &linenum);
jl_value_t *temp = jl_new_struct(jl_linenumbernode_type,
filename, linenum);
JL_GC_POP();
return temp;
}
if (sym == label_sym) {
return jl_new_struct(jl_labelnode_type,
Expand Down Expand Up @@ -459,8 +464,14 @@ static value_t julia_to_scm_(jl_value_t *v)
fl_free_gc_handles(1);
return scmv;
}
if (jl_typeis(v, jl_linenumbernode_type))
return julia_to_list2((jl_value_t*)line_sym, jl_fieldref(v,0));
if (jl_typeis(v, jl_linenumbernode_type)) {
value_t args = julia_to_list2(jl_fieldref(v,1), jl_fieldref(v,0));
fl_gc_handle(&args);
value_t hd = julia_to_scm_((jl_value_t*)line_sym);
value_t scmv = fl_cons(hd, args);
fl_free_gc_handles(1);
return scmv;
}
if (jl_typeis(v, jl_labelnode_type))
return julia_to_list2((jl_value_t*)label_sym, jl_fieldref(v,0));
if (jl_typeis(v, jl_gotonode_type))
Expand Down
2 changes: 1 addition & 1 deletion src/builtins.c
Expand Up @@ -1490,7 +1490,7 @@ size_t jl_static_show_x(JL_STREAM *out, jl_value_t *v, int depth)
n += jl_printf(out, ")");
}
else if (jl_is_linenode(v)) {
n += jl_printf(out, "# line %" PRIuPTR, jl_linenode_line(v));
n += jl_printf(out, "# line %"PRIuPTR" %s", jl_linenode_line(v), jl_linenode_file(v)->name);
}
else if (jl_is_expr(v)) {
jl_expr_t *e = (jl_expr_t*)v;
Expand Down

0 comments on commit 0a91769

Please sign in to comment.