Is there a way to interrogate the Julia runtime and determine places where a method has been called from?
(Context: Emacs development environment for Julia. This is for implementing search by cross-references.)
Is there a way to interrogate the Julia runtime and determine places where a method has been called from?
(Context: Emacs development environment for Julia. This is for implementing search by cross-references.)
You could potentially use Casette.jl to store the stacktrace every time a particular method is called. Apart from this, I do not think any such functionality exists.
For code that has been executed, you can look at the backedges:
julia> foo(::Integer) = 1
foo (generic function with 1 method)
julia> foo(::AbstractFloat) = 2
foo (generic function with 2 methods)
julia> m = @which foo(1)
foo(::Integer) in Main at REPL[1]:1
julia> m.specializations # no specializations (yet)
julia> bar(x) = foo(x)
bar (generic function with 1 method)
julia> bar(1) # execute it, which forces compilation which requires specialization
1
julia> m.specializations # now there are specializations (linked list, see the `next` field also)
Core.TypeMapEntry(nothing, Tuple{typeof(foo),Int64}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for foo(::Int64), true, true, false)
julia> mi = m.specializations.func # the MethodInstance for the first specialization
MethodInstance for foo(::Int64)
julia> mi.backedges # here's the list of MethodInstances that require this specialization
1-element Array{Any,1}:
MethodInstance for bar(::Int64)
For code that hasn’t been executed, it’s difficult to answer even in principle because the same bar
might call a different method of foo
given different input types. You could search for all calls that have the proper number of arguments by iterating through all names in a module, for the functions then iterating through each method, call Base.uncompressed_ast
on the method and then iterate through the code
lines to look for the calls. This would give you a superset of things that call the given method from that module.
You could be a bit more selective by calling code_llvm
on each method with its signature-restricted types; that would force inference and generation of backedges for the broadest possible types supported by each method. But I doubt you’d want to wait for the amount of computation that would require—I would guess that running that on Base
would take many minutes (inference is slow, whereas accessing the lowered code via Base.uncompressed_ast
is pretty fast).
Fantastic info. Thank you very much!