Skip to content

Commit

Permalink
changes needed to adapt to compressed line table format in Julia
Browse files Browse the repository at this point in the history
  • Loading branch information
vtjnash authored and aviatesk committed Mar 21, 2024
1 parent 31253a0 commit 16b332c
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 26 deletions.
2 changes: 1 addition & 1 deletion src/construct.jl
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ function prepare_framecode(method::Method, @nospecialize(argtypes); enter_genera
if (!isempty(lenv) && (hasarg(isidentical(:llvmcall), code.code) ||
hasarg(isidentical(Base.llvmcall), code.code) ||
hasarg(a->is_global_ref(a, Base, :llvmcall), code.code))) ||
hasarg(isidentical(:iolock_begin), code.code)
hasarg(isidentical(:iolock_begin), code.code)
return Compiled()
end
framecode = FrameCode(method, code; generator=generator)
Expand Down
25 changes: 18 additions & 7 deletions src/interpret.jl
Original file line number Diff line number Diff line change
Expand Up @@ -460,13 +460,24 @@ function coverage_visit_line!(frame::Frame)
pc, code = frame.pc, frame.framecode
code.report_coverage || return
src = code.src
codeloc = src.codelocs[pc]
if codeloc != frame.last_codeloc && codeloc != 0
linetable = src.linetable::Vector{Any}
lineinfo = linetable[codeloc]::Core.LineInfoNode
file, line = String(lineinfo.file), lineinfo.line
ccall(:jl_coverage_visit_line, Cvoid, (Cstring, Csize_t, Cint), file, sizeof(file), line)
frame.last_codeloc = codeloc
@static if VERSION v"1.12.0-DEV.173"
lineinfo = linetable(src.debuginfo, pc)
file, line = lineinfo.file, lineinfo.line
if line != frame.last_codeloc
file isa Symbol || (file = Symbol(file))
ccall(:jl_coverage_visit_line, Cvoid, (Cstring, Csize_t, Cint), file, sizeof(file), line)
frame.last_codeloc = codeloc

Check warning on line 469 in src/interpret.jl

View check run for this annotation

Codecov / codecov/patch

src/interpret.jl#L463-L469

Added lines #L463 - L469 were not covered by tests
end
else
codeloc = src.codelocs[pc]
if codeloc != frame.last_codeloc && codeloc != 0
linetable = src.linetable::Vector{Any}
lineinfo = linetable[codeloc]::Core.LineInfoNode
file, line = lineinfo.file, lineinfo.line
file isa Symbol || (file = Symbol(file))
ccall(:jl_coverage_visit_line, Cvoid, (Cstring, Csize_t, Cint), file, sizeof(file), line)
frame.last_codeloc = codeloc

Check warning on line 479 in src/interpret.jl

View check run for this annotation

Codecov / codecov/patch

src/interpret.jl#L472-L479

Added lines #L472 - L479 were not covered by tests
end
end
end

Expand Down
21 changes: 18 additions & 3 deletions src/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,23 @@ function FrameCode(scope, src::CodeInfo; generator=false, optimize=true)

lt = linetable(src)
unique_files = Set{Symbol}()
for entry in lt
push!(unique_files, entry.file)
@static if VERSION v"1.12.0-DEV.173"

Check warning on line 150 in src/types.jl

View check run for this annotation

Codecov / codecov/patch

src/types.jl#L150

Added line #L150 was not covered by tests
function pushuniquefiles!(unique_files, lt)
for edge in lt.edges
pushuniquefiles!(unique_files, edge)
end
linetable = lt.linetable
if linetable === nothing
push!(unique_files, Base.IRShow.debuginfo_file1(lt))
else
pushuniquefiles!(unique_files, linetable)
end
end
pushuniquefiles!(unique_files, lt)
else
for entry in lt
push!(unique_files, entry.file)
end
end

framecode = FrameCode(scope, src, methodtables, breakpoints, slotnamelists, used, generator, report_coverage, unique_files)
Expand Down Expand Up @@ -237,7 +252,7 @@ mutable struct Frame
assignment_counter::Int64
caller::Union{Frame,Nothing}
callee::Union{Frame,Nothing}
last_codeloc::Int32
last_codeloc::Int
end
function Frame(framecode::FrameCode, framedata::FrameData, pc=1, caller=nothing)
if length(junk_frames) > 0
Expand Down
75 changes: 62 additions & 13 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -258,26 +258,74 @@ end

# These getters improve inference since fieldtype(CodeInfo, :linetable)
# and fieldtype(CodeInfo, :codelocs) are both Any
const LineTypes = Union{LineNumberNode,Core.LineInfoNode}
@static if VERSION v"1.12.0-DEV.173"
const LineTypes = Base.IRShow.LineInfoNode
else
const LineTypes = Union{LineNumberNode,Core.LineInfoNode}
end
function linetable(arg)
if isa(arg, Frame)
arg = arg.framecode
end
if isa(arg, FrameCode)
arg = arg.src
end
return (arg::CodeInfo).linetable::Union{Vector{Core.LineInfoNode},Vector{Any}} # issue #264
ci = arg::CodeInfo
@static if VERSION v"1.12.0-DEV.173"

Check warning on line 274 in src/utils.jl

View check run for this annotation

Codecov / codecov/patch

src/utils.jl#L274

Added line #L274 was not covered by tests
return ci.debuginfo
else
return ci.linetable::Union{Vector{Core.LineInfoNode},Vector{Any}} # issue #264
end
end
_linetable(list::Vector, i::Integer) = list[i]::Union{Expr,LineTypes}
function linetable(arg, i::Integer; macro_caller::Bool=false)::Union{Expr,LineTypes}
lt = linetable(arg)
lineinfo = _linetable(lt, i)
if macro_caller
while lineinfo isa Core.LineInfoNode && lineinfo.method === Symbol("macro expansion") && lineinfo.inlined_at != 0
lineinfo = _linetable(lt, lineinfo.inlined_at)
@static if VERSION v"1.12.0-DEV.173"

Check warning on line 283 in src/utils.jl

View check run for this annotation

Codecov / codecov/patch

src/utils.jl#L283

Added line #L283 was not covered by tests
# TODO: decode the linetable at this frame efficiently by reimplementing this here
# TODO: get the contextual name from the parent, rather than returning "n/a" (which breaks Cthulhu)
return Base.IRShow.buildLineInfoNode(lt, :var"n/a", i)[1] # ignore all inlining / macro expansion / etc :(
else
lineinfo = _linetable(lt, i)
if macro_caller
while lineinfo isa Core.LineInfoNode && lineinfo.method === Symbol("macro expansion") && lineinfo.inlined_at != 0
lineinfo = _linetable(lt, lineinfo.inlined_at)
end
end
return lineinfo
end
end

@static if VERSION v"1.12.0-DEV.173"
function linetable_max(lt::Core.DebugInfo)
while true
ltnext = lt.linetable
ltnext === nothing && break
lt = ltnext
end
lastline = 0
for k = 0:typemax(Int)
codeloc = Base.IRShow.getdebugidx(lt, k)
line::Int = codeloc[1]
line < 0 && break
lastline = max(lastline, line)
end
return lastline

Check warning on line 312 in src/utils.jl

View check run for this annotation

Codecov / codecov/patch

src/utils.jl#L299-L312

Added lines #L299 - L312 were not covered by tests
end
function codelocs(arg, i::Integer)
lt = linetable(arg)
codeloc = Base.IRShow.getdebugidx(lt, i)
line::Int = codeloc[1]
line < 0 && return 0 # broken or disabled debug info?
if line == 0 && codeloc[2] == 0
return 0 # no line number update

Check warning on line 320 in src/utils.jl

View check run for this annotation

Codecov / codecov/patch

src/utils.jl#L314-L320

Added lines #L314 - L320 were not covered by tests
end
return lineinfo
return Int(i)

Check warning on line 322 in src/utils.jl

View check run for this annotation

Codecov / codecov/patch

src/utils.jl#L322

Added line #L322 was not covered by tests
end

else # VERSION ≥ v"1.12.0-DEV.173"

function linetable_max(lt::Vector)
return getline(lt[end])
end

function codelocs(arg)
Expand All @@ -289,7 +337,8 @@ function codelocs(arg)
end
return (arg::CodeInfo).codelocs::Vector{Int32}
end
codelocs(arg, i::Integer) = codelocs(arg)[i] # for consistency with linetable (but no extra benefit here)
codelocs(arg, i::Integer) = codelocs(arg)[i]
end # VERSION ≥ v"1.12.0-DEV.173"

function lineoffset(framecode::FrameCode)
offset = 0
Expand Down Expand Up @@ -367,7 +416,7 @@ function codelocation(code::CodeInfo, idx::Int)
idx′ = idx
# look ahead if we are on a meta line
while idx′ < length(code.code)
codeloc = codelocs(code)[idx′]
codeloc = codelocs(code, idx′)
codeloc == 0 || return codeloc
ex = code.code[idx′]
ex === nothing || isexpr(ex, :meta) || break
Expand All @@ -377,7 +426,7 @@ function codelocation(code::CodeInfo, idx::Int)
# if zero, look behind until we find where we last might have had a line
while idx′ > 0
ex = code.code[idx′]
codeloc = codelocs(code)[idx′]
codeloc = codelocs(code, idx′)
codeloc == 0 || return codeloc
idx′ -= 1
end
Expand All @@ -390,8 +439,8 @@ function compute_corrected_linerange(method::Method)
offset = line1 - method.line
@assert !is_generated(method)
src = JuliaInterpreter.get_source(method)
lastline = linetable(src)[end]::LineTypes
return line1:getline(lastline) + offset
lastline = linetable_max(linetable(src))
return line1:lastline + offset
end

function compute_linerange(framecode)
Expand Down Expand Up @@ -508,7 +557,7 @@ function print_framecode(io::IO, framecode::FrameCode; pc=0, range=1:nstatements
ndstmt = ndigits(nstatements(framecode))
lt = linetable(framecode)
offset = lineoffset(framecode)
ndline = isempty(lt) ? 0 : ndigits(getline(lt[end]) + offset)
ndline = ndigits(linetable_max(lt) + offset)
nullline = " "^ndline
src = copy(framecode.src)
replace_coretypes!(src; rev=true)
Expand Down
3 changes: 1 addition & 2 deletions test/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ struct Aborted # for signaling that some statement or test blocks were interr
end

function Aborted(frame::Frame, pc)
src = frame.framecode.src
lineidx = src.codelocs[pc]
lineidx = JuliaInterpreter.codelocs(frame, pc)
lineinfo = JuliaInterpreter.linetable(frame, lineidx; macro_caller=true)
return Aborted(lineinfo)
end
Expand Down

0 comments on commit 16b332c

Please sign in to comment.