-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Be more careful about iterator invalidation during recursive invalida… #57934
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…tion It is possible for one MethodInstance to have a backedge to itself (`typejoin` is a prime example). This didn't used to be much of a problem prior to #57625 because we would just delete the backedges list at the top of invalidation. However, now that we're more selective, we need to be careful not to move backedges around while a frame higher on the stack may be looking at it. To this end, move the compaction part of the deletion into a separate pass and only delete (but don't move around) backedges while a frame higher on the stack may be looking at it.
#57934) …tion It is possible for one MethodInstance to have a backedge to itself (`typejoin` is a prime example). This didn't used to be much of a problem prior to #57625 because we would just delete the backedges list at the top of invalidation. However, now that we're more selective, we need to be careful not to move backedges around while a frame higher on the stack may be looking at it. To this end, move the compaction part of the deletion into a separate pass and only delete (but don't move around) backedges while a frame higher on the stack may be looking at it. Fixes #57696 (cherry picked from commit d6f5b7f)
Since I see this is queued for backporting, it's worth mentioning that this broke SnoopCompile (the in-progress update for 1.12).
|
Here's a MWE. The distinguishing characteristic is the presence of both a poorly-specialized and f(::Integer) = 1
callsfrts(x) = f(Base.inferencebarrier(x)::Signed)
invokesfs(x) = invoke(f, Tuple{Signed}, x)
# compilation
invokesfs(1) # invoked callee
callsfrts(1) # runtime-dispatched callee
# invalidation
logmeths = ccall(:jl_debug_method_invalidation, Any, (Cint,), 1);
f(::Int) = 2
f(::Signed) = 4
ccall(:jl_debug_method_invalidation, Any, (Cint,), 0);
m = which(f, (Signed,))
m ∈ logmeths You want the final line to be Here's the backedge graph before invalidation: julia> m = only(methods(f))
f(::Integer)
@ Main REPL[1]:1
julia> mis = collect(Base.specializations(m))
2-element Vector{Any}:
MethodInstance for f(::Int64)
MethodInstance for f(::Signed)
julia> mi = mis[1]
MethodInstance for f(::Int64)
julia> mi.backedges
2-element Vector{Any}:
Tuple{typeof(f), Signed}
CodeInstance for MethodInstance for invokesfs(::Int64)
julia> mi2 = mis[2]
MethodInstance for f(::Signed)
julia> mi2.backedges
1-element Vector{Any}:
CodeInstance for MethodInstance for callsfrts(::Int64) |
Filed as #58080 so it doesn't get lost |
This is already backported in #57972. |
…tion
It is possible for one MethodInstance to have a backedge to itself (
typejoin
is a prime example). This didn't used to be much of a problem prior to #57625 because we would just delete the backedges list at the top of invalidation. However, now that we're more selective, we need to be careful not to move backedges around while a frame higher on the stack may be looking at it. To this end, move the compaction part of the deletion into a separate pass and only delete (but don't move around) backedges while a frame higher on the stack may be looking at it.Fixes #57696