Skip to content

Commit

Permalink
internals: support line-numbers describing a Method instead of just name
Browse files Browse the repository at this point in the history
Not yet enabled, since we likely need to cache this more efficiently first.
  • Loading branch information
vtjnash committed Feb 13, 2019
1 parent c8510e3 commit 2e37784
Show file tree
Hide file tree
Showing 13 changed files with 111 additions and 77 deletions.
7 changes: 3 additions & 4 deletions base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,7 @@
#end

#struct LineInfoNode
# mod::Module
# method::Symbol
# method::Any
# file::Symbol
# line::Int
# inlined_at::Int
Expand Down Expand Up @@ -375,8 +374,8 @@ eval(Core, :(PiNode(val, typ) = $(Expr(:new, :PiNode, :val, :typ))))
eval(Core, :(PhiCNode(values::Array{Any, 1}) = $(Expr(:new, :PhiCNode, :values))))
eval(Core, :(UpsilonNode(val) = $(Expr(:new, :UpsilonNode, :val))))
eval(Core, :(UpsilonNode() = $(Expr(:new, :UpsilonNode))))
eval(Core, :(LineInfoNode(mod::Module, method::Symbol, file::Symbol, line::Int, inlined_at::Int) =
$(Expr(:new, :LineInfoNode, :mod, :method, :file, :line, :inlined_at))))
eval(Core, :(LineInfoNode(@nospecialize(method), file::Symbol, line::Int, inlined_at::Int) =
$(Expr(:new, :LineInfoNode, :method, :file, :line, :inlined_at))))

Module(name::Symbol=:anonymous, std_imports::Bool=true) = ccall(:jl_f_new_module, Ref{Module}, (Any, Bool), name, std_imports)

Expand Down
4 changes: 1 addition & 3 deletions base/compiler/ssair/driver.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

using Core: LineInfoNode
const NullLineInfo = LineInfoNode(@__MODULE__, Symbol(""), Symbol(""), 0, 0)

if false
import Base: Base, @show
Expand Down Expand Up @@ -103,8 +102,7 @@ function just_construct_ssa(ci::CodeInfo, code::Vector{Any}, nargs::Int, sv::Opt
defuse_insts = scan_slot_def_use(nargs, ci, code)
@timeit "domtree 1" domtree = construct_domtree(cfg)
ir = let code = Any[nothing for _ = 1:length(code)]
argtypes = sv.slottypes[1:(nargs+1)]
IRCode(code, Any[], ci.codelocs, flags, cfg, collect(LineInfoNode, ci.linetable), argtypes, meta, sv.sptypes)
IRCode(code, Any[], ci.codelocs, flags, cfg, collect(LineInfoNode, ci.linetable), sv.slottypes, meta, sv.sptypes)
end
@timeit "construct_ssa" ir = construct_ssa!(ci, code, ir, domtree, defuse_insts, nargs, sv.sptypes, sv.slottypes)
return ir
Expand Down
17 changes: 13 additions & 4 deletions base/compiler/ssair/inlining.jl
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ end
function ssa_inlining_pass!(ir::IRCode, linetable::Vector{LineInfoNode}, sv::OptimizationState)
# Go through the function, performing simple ininlingin (e.g. replacing call by constants
# and analyzing legality of inlining).
@timeit "analysis" todo = assemble_inline_todo!(ir, linetable, sv)
@timeit "analysis" todo = assemble_inline_todo!(ir, sv)
isempty(todo) && return ir
# Do the actual inlining for every call we identified
@timeit "execution" ir = batch_inline!(todo, ir, linetable, sv)
Expand Down Expand Up @@ -289,7 +289,7 @@ function ir_inline_item!(compact::IncrementalCompact, idx::Int, argexprs::Vector
# Append the linetable of the inlined function to our line table
inlined_at = Int(compact.result_lines[idx])
for entry in item.linetable
push!(linetable, LineInfoNode(entry.mod, entry.method, entry.file, entry.line,
push!(linetable, LineInfoNode(entry.method, entry.file, entry.line,
(entry.inlined_at > 0 ? entry.inlined_at + linetable_offset : inlined_at)))
end
if item.isva
Expand Down Expand Up @@ -702,7 +702,16 @@ function analyze_method!(idx::Int, @nospecialize(f), @nospecialize(ft), @nospeci
end

@timeit "inline IR inflation" begin
ir2, inline_linetable = inflate_ir(src, linfo), src.linetable
ir2 = inflate_ir(src, linfo)
# prepare inlining linetable with method instance information
inline_linetable = Vector{LineInfoNode}(undef, length(src.linetable))
for i = 1:length(src.linetable)
entry = src.linetable[i]
if entry.inlined_at === 0 && entry.method === method
entry = LineInfoNode(linfo, entry.file, entry.line, entry.inlined_at)
end
inline_linetable[i] = entry
end
end
#verify_ir(ir2)

Expand Down Expand Up @@ -777,7 +786,7 @@ function handle_single_case!(ir::IRCode, stmt::Expr, idx::Int, @nospecialize(cas
nothing
end

function assemble_inline_todo!(ir::IRCode, linetable::Vector{LineInfoNode}, sv::OptimizationState)
function assemble_inline_todo!(ir::IRCode, sv::OptimizationState)
# todo = (inline_idx, (isva, isinvoke, na), method, spvals, inline_linetable, inline_ir, lie)
todo = Any[]
for idx in 1:length(ir.stmts)
Expand Down
1 change: 0 additions & 1 deletion base/compiler/ssair/legacy.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ end
function replace_code_newstyle!(ci::CodeInfo, ir::IRCode, nargs::Int)
@assert isempty(ir.new_nodes)
# All but the first `nargs` slots will now be unused
resize!(ci.slotnames, nargs+1)
resize!(ci.slotflags, nargs+1)
ci.code = ir.stmts
ci.codelocs = ir.lines
Expand Down
68 changes: 42 additions & 26 deletions base/compiler/ssair/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,12 @@ function default_expr_type_printer(io::IO, @nospecialize(typ), used::Bool)
nothing
end

normalize_method_name(m::Method) = m.name
normalize_method_name(m::MethodInstance) = (m.def::Method).name
normalize_method_name(m::Symbol) = m
normalize_method_name(m) = Symbol("")
@noinline method_name(m::LineInfoNode) = normalize_method_name(m.method)

# converts the linetable for line numbers
# into a list in the form:
# 1 outer-most-frame
Expand Down Expand Up @@ -266,7 +272,7 @@ function compute_ir_line_annotations(code::Union{IRCode, CodeInfo})
# be a line number mismatch in inner most frame. Ignore those
if length(last_stack) == length(stack) && first_mismatch == length(stack)
last_entry, entry = linetable[last_stack[end]], linetable[stack[end]]
if last_entry.method == entry.method && last_entry.file == entry.file
if method_name(last_entry) === method_name(entry) && last_entry.file === entry.file
first_mismatch = nothing
end
end
Expand Down Expand Up @@ -299,13 +305,14 @@ function compute_ir_line_annotations(code::Union{IRCode, CodeInfo})
print(buf, "")
end
end
print(buf, ""^max(0,depth-last_depth-stole_one))
print(buf, ""^max(0, depth - last_depth - stole_one))
if printing_depth != 0
if length(stack) == printing_depth
loc_method = String(linetable[line].method)
loc_method = line
else
loc_method = String(linetable[stack[printing_depth+1]].method)
loc_method = stack[printing_depth + 1]
end
loc_method = method_name(linetable[loc_method])
end
loc_method = string(" "^printing_depth, loc_method)
end
Expand All @@ -326,14 +333,14 @@ Base.show(io::IO, code::IRCode) = show_ir(io, code)

lineinfo_disabled(io::IO, linestart::String, lineidx::Int32) = ""

function DILineInfoPrinter(linetable::Vector)
function DILineInfoPrinter(linetable::Vector, showtypes::Bool=false)
context = LineInfoNode[]
context_depth = Ref(0)
indent(s::String) = s^(max(context_depth[], 1) - 1)
function emit_lineinfo_update(io::IO, linestart::String, lineidx::Int32)
# internal configuration options:
linecolor = :yellow
collapse = true
collapse = showtypes ? false : true
indent_all = true
# convert lineidx to a vector
if lineidx < 0
Expand Down Expand Up @@ -373,11 +380,11 @@ function DILineInfoPrinter(linetable::Vector)
# if so, drop all existing calls to it from the top of the context
# AND check if instead the context was previously printed that way
# but now has removed the recursive frames
let method = context[nctx].method
if (nctx < nframes && DI[nframes - nctx].method === method) ||
(nctx < length(context) && context[nctx + 1].method === method)
let method = method_name(context[nctx])
if (nctx < nframes && method_name(DI[nframes - nctx]) === method) ||
(nctx < length(context) && method_name(context[nctx + 1]) === method)
update_line_only = true
while nctx > 0 && context[nctx].method === method
while nctx > 0 && method_name(context[nctx]) === method
nctx -= 1
end
end
Expand All @@ -388,9 +395,9 @@ function DILineInfoPrinter(linetable::Vector)
# compute the new inlining depth
if collapse
npops = 1
let Prev = context[nctx + 1].method
let Prev = method_name(context[nctx + 1])
for i = (nctx + 2):length(context)
Next = context[i].method
Next = method_name(context[i])
Prev === Next || (npops += 1)
Prev = Next
end
Expand All @@ -402,9 +409,8 @@ function DILineInfoPrinter(linetable::Vector)
if !update_line_only && nctx < nframes
let CtxLine = context[nctx + 1],
FrameLine = DI[nframes - nctx]
if CtxLine.file == FrameLine.file &&
CtxLine.method == FrameLine.method &&
CtxLine.mod == FrameLine.mod
if CtxLine.file === FrameLine.file &&
method_name(CtxLine) === method_name(FrameLine)
update_line_only = true
end
end
Expand All @@ -426,12 +432,12 @@ function DILineInfoPrinter(linetable::Vector)
if frame.line != typemax(frame.line) && frame.line != 0
print(io, linestart)
Base.with_output_color(linecolor, io) do io
print(io, indent(""), " @ ", frame.file, ":", frame.line, " within `", frame.method, "'")
print(io, indent(""), " @ ", frame.file, ":", frame.line, " within `", method_name(frame), "'")
if collapse
method = frame.method
method = method_name(frame)
while nctx < nframes
frame = DI[nframes - nctx]
frame.method === method || break
method_name(frame) === method || break
nctx += 1
push!(context, frame)
print(io, " @ ", frame.file, ":", frame.line)
Expand All @@ -444,23 +450,33 @@ function DILineInfoPrinter(linetable::Vector)
# now print the rest of the new frames
while nctx < nframes
frame = DI[nframes - nctx]
nctx += 1
started = false
if showtypes && !isa(frame.method, Symbol) && nctx != 1
print(io, linestart)
Base.with_output_color(linecolor, io) do io
print(io, indent(""))
print(io, "┌ invoke ", frame.method)
println(io)
end
started = true
end
print(io, linestart)
Base.with_output_color(linecolor, io) do io
print(io, indent(""))
nctx += 1
push!(context, frame)
context_depth[] += 1
nctx != 1 && print(io, "")
nctx != 1 && print(io, started ? "" : "")
print(io, " @ ", frame.file)
if frame.line != typemax(frame.line) && frame.line != 0
print(io, ":", frame.line)
end
print(io, " within `", frame.method, "'")
print(io, " within `", method_name(frame), "'")
if collapse
method = frame.method
method = method_name(frame)
while nctx < nframes
frame = DI[nframes - nctx]
frame.method === method || break
method_name(frame) === method || break
nctx += 1
push!(context, frame)
print(io, " @ ", frame.file, ":", frame.line)
Expand All @@ -471,10 +487,10 @@ function DILineInfoPrinter(linetable::Vector)
end
# FOR DEBUGGING `collapse`:
# this double-checks the computation of context_depth
#let Prev = context[1].method,
#let Prev = method_name(context[1]),
# depth2 = 1
# for i = 2:nctx
# Next = context[i].method
# Next = method_name(context[i])
# (collapse && Prev === Next) || (depth2 += 1)
# Prev = Next
# end
Expand Down Expand Up @@ -565,7 +581,7 @@ function show_ir(io::IO, code::IRCode, expr_type_printer=default_expr_type_print
printstyled(io, "\e[$(start_column)G$(rail)\e[1G", color = :light_black)
print(io, bb_guard_rail)
ssa_guard = " "^(maxlength_idx + 4 + (i - 1))
entry_label = "$(ssa_guard)$(entry.method) at $(entry.file):$(entry.line) "
entry_label = "$(ssa_guard)$(method_name(entry)) at $(entry.file):$(entry.line) "
hline = string(""^(start_column-length(entry_label)-length(bb_guard_rail)+max_depth-i), "")
printstyled(io, string(entry_label, hline), "\n"; color=:light_black)
bb_guard_rail = bb_guard_rail_cont
Expand Down
11 changes: 6 additions & 5 deletions base/compiler/typeinfer.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

const COMPILER_TEMP_SYM = Symbol("#temp#")

# build (and start inferring) the inference frame for the linfo
function typeinf(result::InferenceResult, cached::Bool, params::Params)
frame = InferenceState(result, cached, params)
Expand Down Expand Up @@ -123,6 +121,9 @@ function cache_result(result::InferenceResult, min_valid::UInt, max_valid::UInt)
ccall(:jl_isa_compileable_sig, Int32, (Any, Any), result.linfo.specTypes, def) != 0)
if cache_the_tree
# compress code for non-toplevel thunks
nslots = length(inferred_result.slotflags)
resize!(inferred_result.slottypes, nslots)
resize!(inferred_result.slotnames, nslots)
inferred_result = ccall(:jl_compress_ast, Any, (Any, Any), def, inferred_result)
else
inferred_result = nothing
Expand Down Expand Up @@ -553,15 +554,15 @@ function typeinf_ext(linfo::MethodInstance, params::Params)
tree.slotflags = fill(0x00, nargs)
tree.ssavaluetypes = 1
tree.codelocs = Int32[1]
tree.linetable = [LineInfoNode(method.module, method.name, method.file, Int(method.line), 0)]
tree.linetable = [LineInfoNode(method, method.file, Int(method.line), 0)]
tree.inferred = true
tree.ssaflags = UInt8[0]
tree.pure = true
tree.inlineable = true
tree.parent = linfo
tree.rettype = typeof(linfo.inferred_const)
tree.min_world = li.min_world
tree.max_world = li.max_world
tree.min_world = linfo.min_world
tree.max_world = linfo.max_world
i == 2 && ccall(:jl_typeinf_end, Cvoid, ())
return svec(linfo, tree)
elseif isa(inf, CodeInfo)
Expand Down
2 changes: 1 addition & 1 deletion src/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ static jl_value_t *scm_to_julia_(fl_context_t *fl_ctx, value_t e, jl_module_t *m
else if (sym == thunk_sym) {
ex = scm_to_julia_(fl_ctx, car_(e), mod);
assert(jl_is_code_info(ex));
jl_linenumber_to_lineinfo((jl_code_info_t*)ex, mod, jl_symbol("top-level scope"));
jl_linenumber_to_lineinfo((jl_code_info_t*)ex, (jl_value_t*)jl_symbol("top-level scope"));
temp = (jl_value_t*)jl_exprn(sym, 1);
jl_exprargset(temp, 0, ex);
}
Expand Down
43 changes: 27 additions & 16 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5355,19 +5355,19 @@ static std::unique_ptr<Module> emit_function(
if (!JL_FEAT_TEST(ctx, track_allocations))
malloc_log_mode = JL_LOG_NONE;

ctx.file = "<missing>";
StringRef dbgFuncName = ctx.name;
int toplineno = -1;
if (jl_is_method(lam->def.method)) {
toplineno = lam->def.method->line;
if (lam->def.method->file != empty_sym)
ctx.file = jl_symbol_name(lam->def.method->file);
ctx.file = jl_symbol_name(lam->def.method->file);
}
else if (jl_array_len(src->linetable) > 0) {
jl_value_t *locinfo = jl_array_ptr_ref(src->linetable, 0);
ctx.file = jl_symbol_name((jl_sym_t*)jl_fieldref_noalloc(locinfo, 2));
toplineno = jl_unbox_long(jl_fieldref(locinfo, 3));
ctx.file = jl_symbol_name((jl_sym_t*)jl_fieldref_noalloc(locinfo, 1));
toplineno = jl_unbox_long(jl_fieldref(locinfo, 2));
}
if (ctx.file.empty())
ctx.file = "<missing>";
// jl_printf(JL_STDERR, "\n*** compiling %s at %s:%d\n\n",
// jl_symbol_name(ctx.name), ctx.file.str().c_str(), toplineno);

Expand Down Expand Up @@ -5936,25 +5936,36 @@ static std::unique_ptr<Module> emit_function(
std::map<std::tuple<StringRef, StringRef>, DISubprogram*> subprograms;
linetable.resize(nlocs + 1);
for (size_t i = 0; i < nlocs; i++) {
// LineInfoNode(mod::Module, method::Symbol, file::Symbol, line::Int, inlined_at::Int)
// LineInfoNode(mod::Module, method::Any, file::Symbol, line::Int, inlined_at::Int)
jl_value_t *locinfo = jl_array_ptr_ref(src->linetable, i);
DebugLineTable &info = linetable[i + 1];
assert(jl_typeis(locinfo, jl_lineinfonode_type));
jl_module_t *module = (jl_module_t*)jl_fieldref_noalloc(locinfo, 0);
if (module == ctx.module)
info.is_user_code = mod_is_user_mod;
else
info.is_user_code = in_user_mod(module);
jl_sym_t *method = (jl_sym_t*)jl_fieldref_noalloc(locinfo, 1);
jl_sym_t *filesym = (jl_sym_t*)jl_fieldref_noalloc(locinfo, 2);
info.line = jl_unbox_long(jl_fieldref(locinfo, 3));
info.inlined_at = jl_unbox_long(jl_fieldref(locinfo, 4));
jl_value_t *method = jl_fieldref_noalloc(locinfo, 0);
if (jl_is_method_instance(method))
method = ((jl_method_instance_t*)method)->def.value;
jl_sym_t *filesym = (jl_sym_t*)jl_fieldref_noalloc(locinfo, 1);
info.line = jl_unbox_long(jl_fieldref(locinfo, 2));
info.inlined_at = jl_unbox_long(jl_fieldref(locinfo, 3));
assert(info.inlined_at <= i);
if (jl_is_method(method)) {
jl_module_t *module = ((jl_method_t*)method)->module;
if (module == ctx.module)
info.is_user_code = mod_is_user_mod;
else
info.is_user_code = in_user_mod(module);
}
else {
info.is_user_code = (info.inlined_at == 0) ? mod_is_user_mod : linetable.at(info.inlined_at).is_user_code;
}
info.file = jl_symbol_name(filesym);
if (info.file.empty())
info.file = "<missing>";
if (ctx.debug_enabled) {
StringRef fname = jl_symbol_name(method);
StringRef fname;
if (jl_is_method(method))
method = (jl_value_t*)((jl_method_t*)method)->name;
if (jl_is_symbol(method))
fname = jl_symbol_name((jl_sym_t*)method);
if (fname.empty())
fname = "macro expansion";
if (info.inlined_at == 0 && info.file == ctx.file) { // if everything matches, emit a toplevel line number
Expand Down
Loading

0 comments on commit 2e37784

Please sign in to comment.