From 4dcf35786ec164832e1eb961c9cdacae7974a27a Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 8 Mar 2024 01:26:43 -0500 Subject: [PATCH] inference: Don't confuse frames in different interpreters (#53627) Diffractor's abstract interpreter sometimes needs to do side queries using the native interpreter. These are pushed onto the regular inference callstack in anticipation of a future where compiler plugins may want to recurse from the native interpreter back into the Diffractor abstract interpreter. However, this introduced a subtle challenge: When the native interpreter is looking at a frame that is currently on the inference stack, it would treat them as the same, incorrectly merging inference across the two abstract interpreters (which have different semantics and may not be confused). The caches for the two abstract interpreters were already different, so once things are inferred, there's no problem (likely because things were already inferred on the native interpreter), but if not, this could cause subtle and hard to debug problems. --- base/compiler/abstractinterpretation.jl | 4 ++++ base/compiler/inferencestate.jl | 11 +++++++++++ base/compiler/typeinfer.jl | 2 +- base/show.jl | 6 ++++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index 45f4dea1e46e1..00bd8a9310de7 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -689,6 +689,10 @@ function edge_matches_sv(interp::AbstractInterpreter, frame::AbsIntState, if callee_method2 !== inf_method2 return false end + if isa(frame, InferenceState) && cache_owner(frame.interp) !== cache_owner(interp) + # Don't assume that frames in different interpreters are the same + return false + end if !hardlimit || InferenceParams(interp).ignore_recursion_hardlimit # if this is a soft limit, # also inspect the parent of this edge, diff --git a/base/compiler/inferencestate.jl b/base/compiler/inferencestate.jl index 60e55b8ad2cf0..d4c4d94b6db31 100644 --- a/base/compiler/inferencestate.jl +++ b/base/compiler/inferencestate.jl @@ -731,7 +731,16 @@ function empty_backedges!(frame::InferenceState, currpc::Int=frame.currpc) end function print_callstack(sv::InferenceState) + print("=================== Callstack: ==================\n") + idx = 0 while sv !== nothing + print("[") + print(idx) + if !isa(sv.interp, NativeInterpreter) + print(", ") + print(typeof(sv.interp)) + end + print("] ") print(sv.linfo) is_cached(sv) || print(" [uncached]") println() @@ -740,7 +749,9 @@ function print_callstack(sv::InferenceState) println() end sv = sv.parent + idx += 1 end + print("================= End callstack ==================\n") end function narguments(sv::InferenceState, include_va::Bool=true) diff --git a/base/compiler/typeinfer.jl b/base/compiler/typeinfer.jl index b659fc2a88e6c..3ec9c1a3811ed 100644 --- a/base/compiler/typeinfer.jl +++ b/base/compiler/typeinfer.jl @@ -746,7 +746,7 @@ function merge_call_chain!(interp::AbstractInterpreter, parent::InferenceState, end function is_same_frame(interp::AbstractInterpreter, mi::MethodInstance, frame::InferenceState) - return mi === frame_instance(frame) + return mi === frame_instance(frame) && cache_owner(interp) === cache_owner(frame.interp) end function poison_callstack!(infstate::InferenceState, topmost::InferenceState) diff --git a/base/show.jl b/base/show.jl index df429830b16fd..33832f898d240 100644 --- a/base/show.jl +++ b/base/show.jl @@ -2888,6 +2888,12 @@ show(io::IO, ::Core.Compiler.NativeInterpreter) = show(io::IO, cache::Core.Compiler.CachedMethodTable) = print(io, typeof(cache), "(", Core.Compiler.length(cache.cache), " entries)") +function show(io::IO, limited::Core.Compiler.LimitedAccuracy) + print(io, "Core.Compiler.LimitedAccuracy(") + show(io, limited.typ) + print(io, ", #= ", Core.Compiler.length(limited.causes), " cause(s) =#)") +end + function dump(io::IOContext, x::SimpleVector, n::Int, indent) if isempty(x) print(io, "empty SimpleVector")