Skip to content
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

[release-1.11] Avoid dropping call edges in presence of identical invoke edges #57077

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/staticdata_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,8 @@ static void jl_collect_edges(jl_array_t *edges, jl_array_t *ext_targets, jl_arra
// (invokeTypes, c) => invoke
// (nullptr, invokeTypes) => missing call
// (invokeTypes, nullptr) => missing invoke (unused--inferred as Any)
void *target = ptrhash_get(&edges_map2, invokeTypes ? (void*)invokeTypes : (void*)callee);
void *key = invokeTypes ? (void*)invokeTypes : (void*)callee;
void *target = ptrhash_get(&edges_map2, key);
if (target == HT_NOTFOUND) {
size_t min_valid = 0;
size_t max_valid = ~(size_t)0;
Expand Down Expand Up @@ -551,7 +552,7 @@ static void jl_collect_edges(jl_array_t *edges, jl_array_t *ext_targets, jl_arra
jl_array_ptr_1d_push(ext_targets, callee);
jl_array_ptr_1d_push(ext_targets, matches);
target = (void*)((char*)HT_NOTFOUND + jl_array_nrows(ext_targets) / 3);
ptrhash_put(&edges_map2, (void*)callee, target);
ptrhash_put(&edges_map2, key, target);
}
idxs[++nt] = (char*)target - (char*)HT_NOTFOUND - 1;
}
Expand Down
39 changes: 38 additions & 1 deletion test/precompile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1107,6 +1107,17 @@ precompile_test_harness("invoke") do dir
f44320(::Any) = 2
g44320() = invoke(f44320, Tuple{Any}, 0)
g44320()
# Issue #57115
f57115(@nospecialize(::Any)) = error("unimplemented")
function g57115(@nospecialize(x))
if @noinline rand(Bool)
# Add an 'invoke' edge from 'foo' to 'bar'
Core.invoke(f57115, Tuple{Any}, x)
else
# ... and also an identical 'call' edge
@noinline f57115(x)
end
end

# Adding new specializations should not invalidate `invoke`s
function getlast(itr)
Expand All @@ -1123,6 +1134,8 @@ precompile_test_harness("invoke") do dir
"""
module $CallerModule
using $InvokeModule
import $InvokeModule: f57115, g57115

# involving external modules
callf(x) = f(x)
callg(x) = x < 5 ? g(x) : invoke(g, Tuple{Real}, x)
Expand All @@ -1143,6 +1156,8 @@ precompile_test_harness("invoke") do dir

# Issue #44320
f44320(::Real) = 3
# Issue #57115
f57115(::Int) = 1

call_getlast(x) = getlast(x)

Expand All @@ -1163,6 +1178,7 @@ precompile_test_harness("invoke") do dir
internalnc(3)
call_getlast([1,2,3])
end
precompile(g57115, (Any,))

# Now that we've precompiled, invalidate with a new method that overrides the `invoke` dispatch
$InvokeModule.h(x::Integer) = -1
Expand All @@ -1183,7 +1199,7 @@ precompile_test_harness("invoke") do dir
for m in methods(func)
m.sig.parameters[end] === T && return m
end
error("no ::Real method found for $func")
error("no ::$T method found for $func")
end
function nvalid(mi::Core.MethodInstance)
isdefined(mi, :cache) || return 0
Expand Down Expand Up @@ -1229,6 +1245,27 @@ precompile_test_harness("invoke") do dir
m = only(methods(M.g44320))
@test (m.specializations::Core.MethodInstance).cache.max_world == typemax(UInt)

m = only(methods(M.g57115))
mi = m.specializations::Core.MethodInstance

f_m = get_method_for_type(M.f57115, Any)
f_mi = f_m.specializations::Core.MethodInstance

# Make sure that f57115(::Any) has a 'call' backedge to 'g57115'
has_f_call_backedge = false
it = Core.Compiler.BackedgeIterator(f_mi.backedges)
# Manually-written iterate(...) protocol, since this is in Core.Compiler
item = Core.Compiler.iterate(it)
while item !== nothing
(; sig, caller) = item[1]
if sig === nothing && caller === mi
has_f_call_backedge = true
break
end
item = Core.Compiler.iterate(it, item[2])
end
@test has_f_call_backedge

m = which(MI.getlast, (Any,))
@test (m.specializations::Core.MethodInstance).cache.max_world == typemax(UInt)

Expand Down
Loading