Skip to content

Commit 2e7c82d

Browse files
committed
Add a crude print_with_code implementation on <Julia1.6
Also has small code cleanups and enhancements
1 parent f1d3736 commit 2e7c82d

File tree

2 files changed

+63
-23
lines changed

2 files changed

+63
-23
lines changed

src/codeedges.jl

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,17 @@ if isdefined(Base.IRShow, :show_ir_stmt)
123123
return nothing
124124
end
125125
else
126-
print_with_code(preprint, postprint, io::IO, src::CodeInfo) = print(io, "No IR statement printer available on this version of Julia")
126+
function print_with_code(preprint, postprint, io::IO, src::CodeInfo)
127+
println(io, "No IR statement printer available on this version of Julia, just aligning statements.")
128+
preprint(io)
129+
for idx = 1:length(src.code)
130+
preprint(io, idx)
131+
print(io, src.code[idx])
132+
println(io)
133+
postprint(io, idx, false)
134+
end
135+
postprint(io)
136+
end
127137
end
128138

129139
"""
@@ -185,7 +195,7 @@ function direct_links!(cl::CodeLinks, src::CodeInfo)
185195
for (i, stmt) in enumerate(src.code)
186196
if isexpr(stmt, :thunk) && isa(stmt.args[1], CodeInfo)
187197
icl = CodeLinks(stmt.args[1])
188-
for (name, assigns) in icl.nameassigns
198+
for (name, _) in icl.nameassigns
189199
assign = get(cl.nameassigns, name, nothing)
190200
if assign === nothing
191201
cl.nameassigns[name] = assign = Int[]
@@ -353,6 +363,12 @@ Analyze `src` and determine the chain of dependencies.
353363
for an object `v::Union{Symbol,GlobalRef}`.
354364
"""
355365
function CodeEdges(src::CodeInfo)
366+
src.inferred && error("supply lowered but not inferred code")
367+
cl = CodeLinks(src)
368+
CodeEdges(src, cl)
369+
end
370+
371+
function CodeEdges(src::CodeInfo, cl::CodeLinks)
356372
function pushall!(dest, src)
357373
for item in src
358374
push!(dest, item)
@@ -463,7 +479,12 @@ function print_with_code(io::IO, src::CodeInfo, edges::CodeEdges)
463479
end
464480
printstyled(io, "\nCode:\n", color=:yellow)
465481
end
466-
preprint(::IO, ::Int) = nothing
482+
@static if isdefined(Base.IRShow, :show_ir_stmt)
483+
preprint(::IO, ::Int) = nothing
484+
else
485+
nd = ndigits(length(src.code))
486+
preprint(io::IO, i::Int) = print(io, lpad(i, nd), " ")
487+
end
467488
postprint(::IO) = nothing
468489
postprint(io::IO, idx::Int, bbchanged::Bool) = postprint_lineedges(io, idx, edges, bbchanged)
469490

@@ -606,6 +627,14 @@ function lines_required!(isrequired::AbstractVector{Bool}, objs, src::CodeInfo,
606627
return isrequired
607628
end
608629

630+
function caller_matches(f, mod, sym)
631+
is_global_ref(f, mod, sym) && return true
632+
if isdefined(mod, sym)
633+
is_quotenode(f, getfield(mod, sym)) && return true
634+
end
635+
return false
636+
end
637+
609638
"""
610639
selective_eval!([recurse], frame::Frame, isrequired::AbstractVector{Bool}, istoplevel=false)
611640
@@ -676,3 +705,12 @@ function print_with_code(io::IO, src::CodeInfo, isrequired::AbstractVector{Bool}
676705

677706
print_with_code(preprint, postprint, io, src)
678707
end
708+
709+
function print_with_code(io::IO, frame::Frame, obj)
710+
src = frame.framecode.src
711+
if isdefined(JuliaInterpreter, :reverse_lookup_globalref!)
712+
src = JuliaInterpreter.copy_codeinfo(src)
713+
JuliaInterpreter.reverse_lookup_globalref!(src.code)
714+
end
715+
print_with_code(io, src, obj)
716+
end

test/codeedges.jl

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using LoweredCodeUtils
22
using LoweredCodeUtils.JuliaInterpreter
3+
using LoweredCodeUtils: caller_matches
34
using JuliaInterpreter: is_global_ref, is_quotenode
45
using Test
56

@@ -17,21 +18,15 @@ function hastrackedexpr(stmt; heads=LoweredCodeUtils.trackedheads)
1718
haseval = false
1819
if isa(stmt, Expr)
1920
if stmt.head === :call
20-
haseval = JuliaInterpreter.hasarg(isequal(:eval), stmt.args)
2121
f = stmt.args[1]
22-
is_global_ref(f, Core, :_typebody!) && return true, haseval
23-
if isdefined(Core, :_typebody!)
24-
is_quotenode(f, Core._typebody!) && return true, haseval
25-
end
26-
is_global_ref(f, Core, :_setsuper!) && return true, haseval
27-
if isdefined(Core, :_setsuper!)
28-
is_quotenode(f, Core._setsuper!) && return true, haseval
29-
end
22+
haseval = f === :eval || (caller_matches(f, Base, :getproperty) && is_quotenode(stmt.args[2], :eval))
23+
caller_matches(f, Core, :_typebody!) && return true, haseval
24+
caller_matches(f, Core, :_setsuper!) && return true, haseval
3025
f === :include && return true, haseval
31-
end
32-
stmt.head heads && return true, haseval
33-
if stmt.head == :thunk
26+
elseif stmt.head === :thunk
3427
any(s->any(hastrackedexpr(s; heads=heads)), stmt.args[1].code) && return true, haseval
28+
elseif stmt.head heads
29+
return true, haseval
3530
end
3631
end
3732
return false, haseval
@@ -87,8 +82,7 @@ end
8782
k = rand()
8883
b = 2*a + 5
8984
end
90-
lwr = Meta.lower(ModSelective, ex)
91-
frame = JuliaInterpreter.prepare_thunk(ModSelective, lwr)
85+
frame = JuliaInterpreter.prepare_thunk(ModSelective, ex)
9286
src = frame.framecode.src
9387
edges = CodeEdges(src)
9488
# Check that the result of direct evaluation agrees with selective evaluation
@@ -127,8 +121,7 @@ end
127121
a2 = 2
128122
end
129123
end
130-
lwr = Meta.lower(ModSelective, ex)
131-
frame = JuliaInterpreter.prepare_thunk(ModSelective, lwr)
124+
frame = JuliaInterpreter.prepare_thunk(ModSelective, ex)
132125
src = frame.framecode.src
133126
edges = CodeEdges(src)
134127
isrequired = lines_required(:a2, src, edges)
@@ -149,8 +142,7 @@ end
149142
y3 = 7
150143
end
151144
end
152-
lwr = Meta.lower(ModSelective, ex)
153-
frame = JuliaInterpreter.prepare_thunk(ModSelective, lwr)
145+
frame = JuliaInterpreter.prepare_thunk(ModSelective, ex)
154146
src = frame.framecode.src
155147
edges = CodeEdges(src)
156148
isrequired = lines_required(:a3, src, edges)
@@ -171,8 +163,7 @@ end
171163
Core.eval(ModEval, ex)
172164
@test ModEval.foo() == 0
173165
@test ModEval.bar() == 1
174-
lwr = Meta.lower(ModSelective, ex)
175-
frame = JuliaInterpreter.prepare_thunk(ModSelective, lwr)
166+
frame = JuliaInterpreter.prepare_thunk(ModSelective, ex)
176167
src = frame.framecode.src
177168
edges = CodeEdges(src)
178169
# Mark just the load of Core.eval
@@ -293,5 +284,16 @@ end
293284
else
294285
@test occursin("No IR statement printer", str)
295286
end
287+
# Works with Frames too
288+
frame = JuliaInterpreter.prepare_thunk(ModSelective, ex)
289+
edges = CodeEdges(frame.framecode.src)
290+
LoweredCodeUtils.print_with_code(io, frame, edges)
291+
str = String(take!(io))
292+
if isdefined(Base.IRShow, :show_ir_stmt)
293+
@test occursin(r"s: assigned on \[\d, \d+\], depends on \[\d+\], and used by \[\d+, \d+, \d+\]", str)
294+
@test count(occursin("preds: [1, $(i-1), $(i+1)], succs: [1, $(i+1)]", str) for i = 1:length(src.code)) == 1
295+
else
296+
@test occursin("No IR statement printer", str)
297+
end
296298
end
297299
end

0 commit comments

Comments
 (0)