Skip to content

Commit fc57e44

Browse files
committed
Fixed renumbering of destination of jump nodes (e.g. GotoIfNot and Goto).
1 parent def0f0b commit fc57e44

File tree

2 files changed

+76
-13
lines changed

2 files changed

+76
-13
lines changed

src/CodeInfoTools.jl

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -96,19 +96,20 @@ end
9696
Get the `Core.Compiler.SlotNumber` associated with the `s::Symbol` in `ci::CodeInfo`. If there is no associated `Core.Compiler.SlotNumber`, returns `nothing`.
9797
""", get_slot)
9898

99-
walk(fn, x) = fn(x)
100-
walk(fn, x::Variable) = fn(x)
101-
walk(fn, x::Core.SlotNumber) = fn(x)
102-
walk(fn, x::Core.NewvarNode) = Core.NewvarNode(walk(fn, x.slot))
103-
walk(fn, x::Core.ReturnNode) = Core.ReturnNode(walk(fn, x.val))
104-
walk(fn, x::Core.GotoNode) = Core.GotoNode(walk(fn, x.label))
105-
walk(fn, x::Core.GotoIfNot) = Core.GotoIfNot(walk(fn, x.cond), walk(fn, x.dest))
106-
walk(fn, x::Expr) = Expr(x.head, map(a -> walk(fn, a), x.args)...)
107-
function walk(fn, x::Vector)
99+
walk(fn, x, guard) = fn(x)
100+
walk(fn, x::Variable, guard) = fn(x)
101+
walk(fn, x::Core.SlotNumber, guard) = fn(x)
102+
walk(fn, x::Core.NewvarNode, guard) = Core.NewvarNode(walk(fn, x.slot, guard))
103+
walk(fn, x::Core.ReturnNode, guard) = Core.ReturnNode(walk(fn, x.val, guard))
104+
walk(fn, x::Core.GotoNode, guard) = Core.GotoNode(walk(fn, x.label, guard))
105+
walk(fn, x::Core.GotoIfNot, guard) = Core.GotoIfNot(walk(fn, x.cond, guard), walk(fn, x.dest, guard))
106+
walk(fn, x::Expr, guard) = Expr(x.head, map(a -> walk(fn, a, guard), x.args)...)
107+
function walk(fn, x::Vector, guard)
108108
map(x) do el
109-
walk(fn, el)
109+
walk(fn, el, guard)
110110
end
111111
end
112+
walk(fn, x) = walk(fn, x, Val(:no_catch))
112113

113114
@doc(
114115
"""
@@ -130,7 +131,7 @@ struct Statement{T}
130131
end
131132
Statement(node::T) where T = Statement(node, Union{})
132133
unwrap(stmt::Statement) = stmt.node
133-
walk(fn, stmt::Statement{T}) where T = Statement(walk(fn, stmt.node), stmt.type)
134+
walk(fn, stmt::Statement{T}, guard) where T = Statement(walk(fn, stmt.node, guard), stmt.type)
134135

135136
const stmt = Statement
136137

@@ -245,17 +246,49 @@ setindex!(c::Canvas, x, v::Variable) = setindex!(c, x, v.id)
245246
function delete!(c::Canvas, idx::Int)
246247
c.code[idx] = nothing
247248
c.defs[idx] = (idx, -1)
249+
return nothing
248250
end
249251
delete!(c::Canvas, v::Variable) = delete!(c, v.id)
250252

251253
_get(d::Dict, c, k) = c
252254
_get(d::Dict, c::Variable, k) = haskey(d, c.id) ? Variable(getindex(d, c.id)) : nothing
255+
function _get(d::Dict, c::Core.GotoIfNot, k)
256+
v = c.dest
257+
if haskey(d, v)
258+
nv = getindex(d, v)
259+
else
260+
nv = findfirst(l -> l > v, d)
261+
if nv === nothing
262+
nv = maximum(d)[1]
263+
end
264+
nv = getindex(d, nv)
265+
end
266+
c = _get(d, c.cond, c.cond)
267+
return Core.GotoIfNot(c, nv)
268+
end
269+
function _get(d::Dict, c::Core.GotoNode, k)
270+
v = c.label
271+
if haskey(d, v)
272+
nv = getindex(d, v)
273+
else
274+
nv = findfirst(l -> l > v, d)
275+
if nv === nothing
276+
nv = maximum(d)[1]
277+
end
278+
nv = getindex(d, nv)
279+
end
280+
return Core.GotoNode(nv)
281+
end
282+
283+
# Override for renumber.
284+
walk(fn, c::Core.GotoIfNot, ::Val{:catch_jumps}) = fn(c)
285+
walk(fn, c::Core.GotoNode, ::Val{:catch_jumps}) = fn(c)
253286

254287
function renumber(c::Canvas)
255288
s = sort(filter(v -> v[2] > 0, c.defs); by = x -> x[2])
256289
d = Dict((s[i][1], i) for i in 1 : length(s))
257290
ind = first.(s)
258-
swap = walk(k -> _get(d, k, k), c.code)
291+
swap = walk(k -> _get(d, k, k), c.code, Val(:catch_jumps))
259292
return Canvas(Tuple{Int, Int}[(i, i) for i in 1 : length(s)],
260293
getindex(swap, ind), getindex(c.codelocs, ind))
261294
end
@@ -424,7 +457,7 @@ end
424457

425458
function Base.delete!(b::Builder, v::Union{Variable, NewVariable})
426459
v′ = substitute(b, v)
427-
delete!(b.to, v′)
460+
substitute!(b, v′, delete!(b.to, v′))
428461
end
429462

430463
function slot!(b::Builder, name::Symbol; arg = false)
@@ -445,6 +478,7 @@ Add a new `Core.SlotNumber` with associated `name::Symbol` to the in-progress `C
445478
`name::Symbol` must not already be associated with a `Core.SlotNumber`.
446479
""", slot!)
447480

481+
return!(b::Builder, v) = push!(b, Core.ReturnNode(v))
448482
return!(b::Builder, v::Variable) = push!(b, Core.ReturnNode(v))
449483
return!(b::Builder, v::NewVariable) = push!(b, Core.ReturnNode(v))
450484

test/misc.jl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,32 @@ end
3636
src = code_inferred(l, Int)
3737
display(src)
3838
end
39+
40+
@testset "Coverage removal -- misc." begin
41+
b = CodeInfoTools.Builder()
42+
push!(b, Expr(:code_coverage_effect))
43+
push!(b, Expr(:code_coverage_effect))
44+
push!(b, Expr(:code_coverage_effect))
45+
push!(b, Expr(:code_coverage_effect))
46+
push!(b, Expr(:call, :foo, 2))
47+
v = push!(b, Expr(:call, :measure, 2))
48+
push!(b, Expr(:code_coverage_effect))
49+
push!(b, Expr(:code_coverage_effect))
50+
k = push!(b, Expr(:call, :measure_cmp, v, 1))
51+
push!(b, Core.GotoIfNot(k, 14))
52+
push!(b, Expr(:code_coverage_effect))
53+
push!(b, Expr(:code_coverage_effect))
54+
push!(b, Expr(:call, :foo, 2))
55+
push!(b, Expr(:code_coverage_effect))
56+
return!(b, nothing)
57+
start = finish(b)
58+
display(start)
59+
new = CodeInfoTools.Builder(start)
60+
for (v, st) in new
61+
if st isa Expr && st.head == :code_coverage_effect
62+
delete!(new, v)
63+
end
64+
end
65+
src = finish(new)
66+
display(src)
67+
end

0 commit comments

Comments
 (0)