From cb9b79a11cad62ebaad70c8c92ade202b15e833c Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 12 Dec 2023 00:54:06 +0000 Subject: [PATCH] changes needed to adapt to compressed line table format in Julia For https://github.com/JuliaLang/julia/pull/52415 --- src/construct.jl | 2 +- src/interpret.jl | 25 +++++++++++----- src/types.jl | 21 ++++++++++++-- src/utils.jl | 75 +++++++++++++++++++++++++++++++++++++++--------- test/utils.jl | 3 +- 5 files changed, 100 insertions(+), 26 deletions(-) diff --git a/src/construct.jl b/src/construct.jl index 4615054d..71352f8e 100644 --- a/src/construct.jl +++ b/src/construct.jl @@ -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) diff --git a/src/interpret.jl b/src/interpret.jl index e3613bf5..cd232c91 100644 --- a/src/interpret.jl +++ b/src/interpret.jl @@ -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 + 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 + end end end diff --git a/src/types.jl b/src/types.jl index 04539fa9..fe0f4bd9 100644 --- a/src/types.jl +++ b/src/types.jl @@ -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" + 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) @@ -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 diff --git a/src/utils.jl b/src/utils.jl index 7923d5f8..7ed54201 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -258,7 +258,11 @@ 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 @@ -266,18 +270,62 @@ function linetable(arg) 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" + 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" + # 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 +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 end - return lineinfo + return Int(i) +end + +else # VERSION ≥ v"1.12.0-DEV.173" + +function linetable_max(lt::Vector) + return getline(lt[end]) end function codelocs(arg) @@ -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 @@ -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 @@ -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 @@ -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) @@ -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) diff --git a/test/utils.jl b/test/utils.jl index 1a3f058e..f1cf69a7 100644 --- a/test/utils.jl +++ b/test/utils.jl @@ -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