From c35cd0abcb8184ee5aa37e1fd3b4b31b48bf691c Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Thu, 15 Aug 2024 03:57:19 -0500 Subject: [PATCH 1/3] Allow a `Tuple{typeof(f),...}` as root of ascend tree Required for https://github.com/aviatesk/JET.jl/pull/648#issuecomment-2280722393 --- Project.toml | 2 +- src/backedges.jl | 4 +++- src/callsite.jl | 10 ++++++++++ src/reflection.jl | 2 +- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Project.toml b/Project.toml index d9786244..b21ad157 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Cthulhu" uuid = "f68482b8-f384-11e8-15f7-abe071a5a75f" authors = ["Valentin Churavy and contributors"] -version = "2.13.0" +version = "2.14.0" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" diff --git a/src/backedges.jl b/src/backedges.jl index ba4aab44..b33cec35 100644 --- a/src/backedges.jl +++ b/src/backedges.jl @@ -147,6 +147,8 @@ specTypes(mi::MethodInstance) = mi.specTypes instance(mi::MethodInstance) = mi nextnode(mi, edge) = edge +instance(@nospecialize(tt::Type)) = tt + instance(sfs::Vector{StackTraces.StackFrame}) = isempty(sfs) ? CC.Timings.ROOTmi : sfs[end].linfo::MethodInstance # we checked this type condition within `buildframes` method(sfs::Vector{StackTraces.StackFrame}) = method(instance(sfs)) backedges(sframes::Vector{StackTraces.StackFrame}) = (ret = sframes[2:end]; isempty(ret) ? () : (ret,)) @@ -188,7 +190,7 @@ function treelist!(parent::Node, io::IO, mi, indent::AbstractString, visited::Ba indent *= " " for edge in backedges(mi) str = indent * callstring(io, edge) - child = Node(Data(str, instance(edge)), parent) + child = Node(typeof(parent.data)(str, instance(edge)), parent) treelist!(child, io, nextnode(mi, edge), indent, visited) end return parent diff --git a/src/callsite.jl b/src/callsite.jl index afa7ce93..9d85286e 100644 --- a/src/callsite.jl +++ b/src/callsite.jl @@ -506,6 +506,7 @@ end # maybe_callsite for higher-level inputs maybe_callsite(cs::Callsite, callee::MethodInstance) = maybe_callsite(cs.info, callee) +maybe_callsite(cs::Callsite, @nospecialize(tt::Type)) = maybe_callsite(cs.info, tt) maybe_callsite(info::CallInfo, callee::MethodInstance) = maybe_callsite(get_mi(info), callee) # Special CallInfo cases: function maybe_callsite(info::MultiCallInfo, callee::MethodInstance) @@ -517,4 +518,13 @@ end maybe_callsite(info::PureCallInfo, mi::MethodInstance) = mi.specTypes <: Tuple{mapany(Core.Typeof ∘ unwrapconst, info.argtypes)...} maybe_callsite(info::RTCallInfo, mi::MethodInstance) = false +function maybe_callsite(info::RTCallInfo, @nospecialize(tt::Type)) + info.f === tt.parameters[1] && info.argtyps == tt.parameters[2:end] +end +function maybe_callsite(info::MICallInfo, @nospecialize(tt::Type)) + info.mi.specTypes <: tt +end + +maybe_callsite(info::CallInfo, @nospecialize(tt::Type)) = false + unwrapconst(@nospecialize(arg)) = arg isa Core.Const ? arg.val : arg diff --git a/src/reflection.jl b/src/reflection.jl index 34eeb374..ca544988 100644 --- a/src/reflection.jl +++ b/src/reflection.jl @@ -299,7 +299,7 @@ function callinfo(sig, rt, max_methods=-1; world=get_world_counter()) return MultiCallInfo(sig, rt, callinfos) end -function find_caller_of(interp::AbstractInterpreter, callee::MethodInstance, caller::MethodInstance; allow_unspecialized::Bool=false) +function find_caller_of(interp::AbstractInterpreter, callee::Union{MethodInstance,Type}, caller::MethodInstance; allow_unspecialized::Bool=false) interp′ = CthulhuInterpreter(interp) do_typeinf!(interp′, caller) locs = Tuple{Core.LineInfoNode,Int}[] From 8ceacfbfda7f10531fe2ef742aa76a05cfdb677d Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Fri, 16 Aug 2024 06:43:56 -0500 Subject: [PATCH 2/3] bail on `Union{}` --- src/callsite.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/callsite.jl b/src/callsite.jl index 9d85286e..0f6f908a 100644 --- a/src/callsite.jl +++ b/src/callsite.jl @@ -519,6 +519,7 @@ maybe_callsite(info::PureCallInfo, mi::MethodInstance) = mi.specTypes <: Tuple{m maybe_callsite(info::RTCallInfo, mi::MethodInstance) = false function maybe_callsite(info::RTCallInfo, @nospecialize(tt::Type)) + tt === Union{} && return false info.f === tt.parameters[1] && info.argtyps == tt.parameters[2:end] end function maybe_callsite(info::MICallInfo, @nospecialize(tt::Type)) From 79d600f9ae854b739bed15bfc9b75445b7a91c2c Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sat, 17 Aug 2024 06:54:52 -0500 Subject: [PATCH 3/3] Fix rt callsite matching --- src/Cthulhu.jl | 3 +++ src/callsite.jl | 11 ++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Cthulhu.jl b/src/Cthulhu.jl index 26189e07..d901270a 100644 --- a/src/Cthulhu.jl +++ b/src/Cthulhu.jl @@ -856,6 +856,9 @@ function ascend(term, mi; interp::AbstractInterpreter=NativeInterpreter(), kwarg end end end + if !isa(mi, MethodInstance) + error("You can only descend into known calls. If you tried to descend into a runtime-dispatched signature, try its caller instead.") + end # The main application of `ascend` is finding cases of non-inferrability, so the # warn highlighting is useful. interp′ = CthulhuInterpreter(interp) diff --git a/src/callsite.jl b/src/callsite.jl index 0f6f908a..a8959a83 100644 --- a/src/callsite.jl +++ b/src/callsite.jl @@ -519,11 +519,16 @@ maybe_callsite(info::PureCallInfo, mi::MethodInstance) = mi.specTypes <: Tuple{m maybe_callsite(info::RTCallInfo, mi::MethodInstance) = false function maybe_callsite(info::RTCallInfo, @nospecialize(tt::Type)) - tt === Union{} && return false - info.f === tt.parameters[1] && info.argtyps == tt.parameters[2:end] + isa(tt, Union) && return maybe_callsite(info, tt.a) || maybe_callsite(info, tt.b) + isa(tt, DataType) || return false + typeof(info.f) === tt.parameters[1] || return false + for (a, b) in zip(info.argtyps, tt.parameters[2:end]) + a === b || return false + end + return true end function maybe_callsite(info::MICallInfo, @nospecialize(tt::Type)) - info.mi.specTypes <: tt + return tt <: info.mi.specTypes end maybe_callsite(info::CallInfo, @nospecialize(tt::Type)) = false