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

Emit inlining information to improve line numbers #12544

Merged
merged 4 commits into from
Sep 4, 2015
Merged
Show file tree
Hide file tree
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
3 changes: 2 additions & 1 deletion base/boot.jl
Original file line number Diff line number Diff line change
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
4 changes: 3 additions & 1 deletion base/cartesian.jl
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,9 @@ 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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this need to work on surface syntax ASTs? (used from macros)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed (I think). Thanks.

return ex.args[2]
elseif (length(ex.args) == 2 && isa(ex.args[1], Expr) && ex.args[1].head == :line)
return ex.args[2]
end
end
Expand Down
2 changes: 1 addition & 1 deletion base/deprecated.jl
Original file line number Diff line number Diff line change
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, inlinedat_file, inlinedat_line, fromC = lkup
if fname == funcsym
break
end
Expand Down
2 changes: 1 addition & 1 deletion base/docs/Docs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the isexpr(:line)test still needed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, in macro expansions we call scm_to_julia_ with expronly=1, so :line (and all other tree nodes) get translated to Exprs.

length(exs) == 1 || return ex
return unblock(exs[1])
end
Expand Down
2 changes: 1 addition & 1 deletion base/essentials.jl
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably make more use of this interface to jl_lookup_code_address.

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
42 changes: 32 additions & 10 deletions base/replutil.jl
Original file line number Diff line number Diff line change
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 @@ -339,19 +339,36 @@ function show_method_candidates(io::IO, ex::MethodError)
end
end

function show_trace_entry(io, fname, file, line, n)
print(io, "\n")
print(io, " in ", fname, " at ", file)
function show_trace_entry(io, fname, file, line, inlinedat_file, inlinedat_line, n)
# if we have inlining information, we print the `file`:`line` first,
# then show the inlining info, because the inlining location
# corresponds to `fname`.
if (inlinedat_file != symbol(""))
# align the location text
print(io, "\n")
print(io, " [inlined code] from ")
else
print(io, " in ", fname, " 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

if (inlinedat_file != symbol(""))
print(io, "\n in ", fname, " at ")
print(io, inlinedat_file, ":", inlinedat_line, "\n")
end
end

function show_backtrace(io::IO, t, set=1:typemax(Int))
Expand All @@ -367,38 +384,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_inlinedat_file, last_inlinedat_line, n) =
show_trace_entry(io, lastname, lastfile, lastline, last_inlinedat_file, last_inlinedat_line, 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_inlinedat_file = ""; last_inlinedat_line = -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, inlinedat_file, inlinedat_line, 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_inlinedat_file, last_inlinedat_line, n)
end
n = 1
lastfile = file; lastline = line; lastname = fname
lastfile = file; lastline = line; lastname = fname;
last_inlinedat_file = inlinedat_file; last_inlinedat_line = inlinedat_line;
else
n += 1
end
end
if n > 1 || lastline != -11
process_func(lastname, lastfile, lastline, n)
process_func(lastname, lastfile, lastline, last_inlinedat_file, last_inlinedat_line, n)
end
end
10 changes: 2 additions & 8 deletions base/show.jl
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
55 changes: 40 additions & 15 deletions src/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,30 +326,49 @@ 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 = NULL, *linenum = NULL;
JL_GC_PUSH2(&filename, &linenum);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note that assuming filename is a Symbol, it doesn't need a root. If it wasn't a symbol, this root would have been needed before the call to create the box to linenum.

filename = scm_to_julia_(car_(cdr_(e)),0);
linenum = scm_to_julia_(car_(e),0);
jl_value_t *temp = jl_new_struct(jl_linenumbernode_type,
filename, linenum);
JL_GC_POP();
return temp;
}
jl_value_t *scmv = NULL, *temp = NULL;
JL_GC_PUSH(&scmv);
if (sym == label_sym) {
return jl_new_struct(jl_labelnode_type,
scm_to_julia_(car_(e),0));
scmv = scm_to_julia_(car_(e),0);
temp = jl_new_struct(jl_labelnode_type, scmv);
JL_GC_POP();
return temp;
}
if (sym == goto_sym) {
return jl_new_struct(jl_gotonode_type,
scm_to_julia_(car_(e),0));
scmv = scm_to_julia_(car_(e),0);
temp = jl_new_struct(jl_gotonode_type, scmv);
JL_GC_POP();
return temp;
}
if (sym == inert_sym || (sym == quote_sym && (!iscons(car_(e))))) {
return jl_new_struct(jl_quotenode_type,
scm_to_julia_(car_(e),0));
scmv = scm_to_julia_(car_(e),0);
temp = jl_new_struct(jl_quotenode_type, scmv);
JL_GC_POP();
return temp;
}
if (sym == top_sym) {
return jl_new_struct(jl_topnode_type,
scm_to_julia_(car_(e),0));
scmv = scm_to_julia_(car_(e),0);
temp = jl_new_struct(jl_topnode_type, scmv);
JL_GC_POP();
return temp;
}
if (sym == newvar_sym) {
return jl_new_struct(jl_newvarnode_type,
scm_to_julia_(car_(e),0));
scmv = scm_to_julia_(car_(e),0);
temp = jl_new_struct(jl_newvarnode_type, scmv);
JL_GC_POP();
return temp;
}
JL_GC_POP();
}
else if (sym == inert_sym && !iscons(car_(e))) {
sym = quote_sym;
Expand Down Expand Up @@ -459,8 +478,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));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think you are still missing a gc-root for args during the call to julia_to_scm_

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

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
Original file line number Diff line number Diff line change
Expand Up @@ -1516,7 +1516,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
Loading