Skip to content

Commit 59a7bb3

Browse files
authored
stored method interference graph (#58948)
Store full method interference relationship graph in interferences field of Method to avoid expensive morespecific calls during dispatch. This provides significant performance improvements: - Replace method comparisons with precomputed interference lookup. - Optimize ml_matches minmax computation using interference lookups. - Optimize sort_mlmatches for large return sets by iterating over interferences instead of all matching methods. - Add method_morespecific_via_interferences in both C and Julia. This representation may exclude some edges that are implied by transitivity since sort_mlmatches will ensure the correct result by following strong edges. Ambiguous edges are guaranteed to be checkable without recursion. Also fix a variety of bugs along the way: - Builtins signature would cause them to try to discard all other methods during `sort_mlmatches`. - Some ambiguities were over-estimated, which now are improved upon. - Setting lim==-1 now gives the same limited list of methods as lim>0, since that is actually faster now than attempting to give the unsorted list. This provides a better fix to #53814 than #57837 and fixes #58766. - Reverts recent METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC attempt (though not the whole commit), since I found a significant problem with any usage of that bit during testing: it only tracks methods that intersect with a target, but new methods do not necessarily intersect with any existing target. This provides a decent performance improvement to `methods` calls, which implies a decent speed up to package loading also (e.g. ModelingToolkit loads in about 4 seconds instead of 5 seconds).
1 parent fae0d0a commit 59a7bb3

File tree

15 files changed

+638
-529
lines changed

15 files changed

+638
-529
lines changed

base/Base.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,9 @@ include("uuid.jl")
267267
include("pkgid.jl")
268268
include("toml_parser.jl")
269269
include("linking.jl")
270+
module StaticData
270271
include("staticdata.jl")
272+
end
271273
include("loading.jl")
272274

273275
# BinaryPlatforms, used by Artifacts. Needs `Sort`.

base/errorshow.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -465,14 +465,15 @@ function show_method_candidates(io::IO, ex::MethodError, kwargs=[])
465465
line_score = Int[]
466466
# These functions are special cased to only show if first argument is matched.
467467
special = f === convert || f === getindex || f === setindex!
468+
f isa Core.Builtin && return # `methods` isn't very useful for a builtin
468469
funcs = Tuple{Any,Vector{Any}}[(f, arg_types_param)]
469470

470471
# An incorrect call method produces a MethodError for convert.
471472
# It also happens that users type convert when they mean call. So
472473
# pool MethodErrors for these two functions.
473474
if f === convert && !isempty(arg_types_param)
474475
at1 = arg_types_param[1]
475-
if isType(at1) && !has_free_typevars(at1)
476+
if isType(at1) && !has_free_typevars(at1) && at1.parameters[1] isa Type
476477
push!(funcs, (at1.parameters[1], arg_types_param[2:end]))
477478
end
478479
end
@@ -494,8 +495,8 @@ function show_method_candidates(io::IO, ex::MethodError, kwargs=[])
494495
end
495496
sig0 = sig0::DataType
496497
s1 = sig0.parameters[1]
497-
if sig0 === Tuple || !isa(func, rewrap_unionall(s1, method.sig))
498-
# function itself doesn't match or is a builtin
498+
if !isa(func, rewrap_unionall(s1, method.sig))
499+
# function itself doesn't match
499500
continue
500501
else
501502
print(iob, " ")
@@ -640,6 +641,7 @@ function show_method_candidates(io::IO, ex::MethodError, kwargs=[])
640641
println(io) # extra newline for spacing to stacktrace
641642
end
642643
end
644+
nothing
643645
end
644646

645647
# In case the line numbers in the source code have changed since the code was compiled,

base/methodshow.jl

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ end
7878

7979
# NOTE: second argument is deprecated and is no longer used
8080
function kwarg_decl(m::Method, kwtype = nothing)
81-
if m.sig !== Tuple # OpaqueClosure or Builtin
81+
if !(m.sig === Tuple || m.sig <: Tuple{Core.Builtin, Vararg}) # OpaqueClosure or Builtin
8282
kwtype = typeof(Core.kwcall)
8383
sig = rewrap_unionall(Tuple{kwtype, NamedTuple, (unwrap_unionall(m.sig)::DataType).parameters...}, m.sig)
8484
kwli = ccall(:jl_methtable_lookup, Any, (Any, UInt), sig, get_world_counter())
@@ -219,8 +219,7 @@ function show_method(io::IO, m::Method;
219219
modulecolor = :light_black, digit_align_width = 1,
220220
print_signature_only::Bool = get(io, :print_method_signature_only, false)::Bool)
221221
tv, decls, file, line = arg_decl_parts(m)
222-
sig = unwrap_unionall(m.sig)
223-
if sig === Tuple
222+
if m.sig <: Tuple{Core.Builtin, Vararg}
224223
# Builtin
225224
print(io, m.name, "(...)")
226225
file = "none"
@@ -425,8 +424,7 @@ end
425424
function show(io::IO, ::MIME"text/html", m::Method)
426425
tv, decls, file, line = arg_decl_parts(m, true)
427426
sig = unwrap_unionall(m.sig)
428-
if sig === Tuple
429-
# Builtin
427+
if sig <: Tuple{Core.Builtin, Vararg}
430428
print(io, m.name, "(...) in ", parentmodule(m))
431429
return
432430
end

base/runtime_internals.jl

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,15 +1515,7 @@ end
15151515
function matches_to_methods(ms::Array{Any,1}, tn::Core.TypeName, mod)
15161516
# Lack of specialization => a comprehension triggers too many invalidations via _collect, so collect the methods manually
15171517
ms = Method[(ms[i]::Core.MethodMatch).method for i in 1:length(ms)]
1518-
# Remove shadowed methods with identical type signatures
1519-
prev = nothing
1520-
filter!(ms) do m
1521-
l = prev
1522-
repeated = (l isa Method && m.sig == l.sig)
1523-
prev = m
1524-
return !repeated
1525-
end
1526-
# Remove methods not part of module (after removing shadowed methods)
1518+
# Remove methods not part of module
15271519
mod === nothing || filter!(ms) do m
15281520
return parentmodule(m) mod
15291521
end

0 commit comments

Comments
 (0)