Skip to content

Commit

Permalink
Merge pull request #12544 from JuliaLang/all-your-filename-are-belong…
Browse files Browse the repository at this point in the history
…-to-linenode

Emit inlining information to improve line numbers
  • Loading branch information
jakebolewski committed Sep 4, 2015
2 parents bcb2858 + 19e765e commit a07d5ee
Show file tree
Hide file tree
Showing 22 changed files with 299 additions and 156 deletions.
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)
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 @@ -90,7 +90,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)
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})
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
print(io,"\n$(code[1]) will only return a complex result if called with a complex argument. Try $(code[1]) (complex(x)).")
elseif (code[1] == :^ && code[2] == symbol("intfuncs.jl")) || code[1] == :power_by_squaring #3024
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);
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));
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 @@ -1500,7 +1500,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

0 comments on commit a07d5ee

Please sign in to comment.