Skip to content

Commit cf4058c

Browse files
authored
Redesign visit (#3)
visit: Bool recursion control, print off by default, etc This makes many changes to `visit`: - it requires `operation` to return a Bool to control descent - it extends the "visit-once" logic to all types - it extends printing to all objects but turns it off by default - it greatly improves performance with nospecialize annotations - it separates user-interface from internals (visit vs _visit) - it supports more types (MethodTable, CodeInstance) Closes #2 Also redesign visit_backedges to exploit new visit. This orthogonalizes the two functions.
1 parent cdd605a commit cf4058c

File tree

6 files changed

+199
-109
lines changed

6 files changed

+199
-109
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ version = "0.1.0"
77
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
88

99
[compat]
10-
julia = "1"
1110
AbstractTrees = "0.3"
11+
julia = "1"
1212

1313
[extras]
1414
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

docs/src/index.md

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
This package facilitates introspection of Julia's internals, with a particular focus on its MethodInstances and their backedges.
44

55
!!! warning
6-
Julia's internals are not subject to the same stability guarantee that the rest of the language enjoys.
6+
Julia's internals are not subject to the same interface compatibility guarantee that the rest of the language enjoys.
77

88
## Demonstrations
99

@@ -16,10 +16,12 @@ julia> using MethodAnalysis
1616
1717
julia> mods = Module[];
1818
19-
julia> visit(Base; print=false) do obj
19+
julia> visit(Base) do obj
2020
if isa(obj, Module)
2121
push!(mods, obj)
22+
return true # descend into submodules
2223
end
24+
false # but don't descend into anything else (MethodTables, etc.)
2325
end
2426
2527
julia> Base.FastMath ∈ mods
@@ -34,15 +36,10 @@ true
3436
julia> meths = []
3537
Any[]
3638
37-
julia> visit(Core.Compiler) do item # without print=false it will display the modules it visits
39+
julia> visit(Core.Compiler) do item
3840
isa(item, Method) && push!(meths, item)
41+
true # walk through everything
3942
end
40-
Module Core.Compiler
41-
Module Core.Compiler.CoreDocs
42-
Module Core.Compiler.Iterators
43-
Module Core.Compiler.Order
44-
Module Core.Compiler.Sort
45-
Module Core.Compiler.Sort.Float
4643
4744
julia> first(methods(Core.Compiler.typeinf_ext)) ∈ meths
4845
true
@@ -72,6 +69,7 @@ julia> mis = Core.MethodInstance[];
7269
7370
julia> visit(findfirst) do item
7471
isa(item, Core.MethodInstance) && length(Base.unwrap_unionall(item.specTypes).parameters) == 2 && push!(mis, item)
72+
true
7573
end
7674
7775
julia> mis

src/MethodAnalysis.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module MethodAnalysis
22

33
using AbstractTrees
44

5+
using Base: Callable, IdSet
56
using Core: MethodInstance, SimpleVector, MethodTable
67

78
export visit, call_type, instance, worlds
@@ -77,7 +78,9 @@ function instance(f, types)
7778
if mi.specTypes === tt
7879
inst = mi
7980
end
81+
return false
8082
end
83+
true
8184
end
8285
return inst
8386
end

src/backedges.jl

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,11 @@ their backedges. The result includes both MethodTable and MethodInstance backedg
1818
"""
1919
function with_all_backedges(iter)
2020
backedges = Set{MethodInstance}()
21-
visited = Set{Union{MethodInstance,MethodTable}}()
21+
visited = IdSet{MethodInstance}()
2222
for item in iter
2323
visit_backedges(item, visited) do edge
2424
if isa(edge, MethodInstance)
2525
push!(backedges, edge)
26-
else
27-
sig, mi = edge
28-
push!(backedges, mi)
2926
end
3027
true
3128
end
@@ -57,26 +54,32 @@ Collect all backedges for a function `f` as pairs `instance=>caller` or `sig=>ca
5754
The latter occur for MethodTable backedges.
5855
If `skip` is `true`, any `caller` listed in a MethodTable backedge is omitted from the instance backedges.
5956
"""
60-
function direct_backedges(f::Function; skip::Bool=true)
57+
function direct_backedges(f::Union{Method,Callable}; skip::Bool=true)
6158
bes = []
6259
_skip = Set{MethodInstance}()
63-
mths = methods(f).ms
64-
callee = nothing
65-
visit_backedges(f) do item
66-
if isa(item, Pair)
67-
push!(bes, item)
68-
push!(_skip, item.second)
60+
visit(f) do item
61+
if isa(item, MethodTable)
62+
mt = item::MethodTable
63+
if isdefined(mt, :backedges)
64+
sigmis = mt.backedges::Vector{Any}
65+
for i = 1:2:length(sigmis)
66+
sig, mi = sigmis[i], sigmis[i+1]
67+
push!(bes, Pair{Any,MethodInstance}(sig, mi))
68+
push!(_skip, mi)
69+
end
70+
end
6971
return false
70-
else
71-
mi = item::MethodInstance
72-
if mi.def mths
73-
callee = mi
74-
return true
75-
else
76-
(!skip || mi _skip) && push!(bes, callee=>mi)
77-
return false
72+
elseif isa(item, MethodInstance)
73+
callee = item::MethodInstance
74+
if isdefined(callee, :backedges)
75+
for caller in callee.backedges
76+
skip && caller _skip && continue
77+
push!(bes, callee=>caller)
78+
end
7879
end
80+
return false
7981
end
82+
true
8083
end
8184
return bes
8285
end

0 commit comments

Comments
 (0)