Skip to content

Commit 32b1b14

Browse files
authored
fix and de-dup cached calls to methods_by_ftype in compiler (#36404)
1 parent 0a70d42 commit 32b1b14

File tree

2 files changed

+35
-33
lines changed

2 files changed

+35
-33
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,25 @@ const _REF_NAME = Ref.body.name
1616
call_result_unused(frame::InferenceState, pc::LineNum=frame.currpc) =
1717
isexpr(frame.src.code[frame.currpc], :call) && isempty(frame.ssavalue_uses[pc])
1818

19+
function matching_methods(@nospecialize(atype), cache::IdDict{Any, Tuple{Any, UInt, UInt}}, max_methods::Int, world::UInt)
20+
box = Core.Box(atype)
21+
return get!(cache, atype) do
22+
_min_val = UInt[typemin(UInt)]
23+
_max_val = UInt[typemax(UInt)]
24+
ms = _methods_by_ftype(box.contents, max_methods, world, _min_val, _max_val)
25+
return ms, _min_val[1], _max_val[1]
26+
end
27+
end
28+
29+
function matching_methods(@nospecialize(atype), cache::IdDict{Any, Tuple{Any, UInt, UInt}}, max_methods::Int, world::UInt, min_valid::Vector{UInt}, max_valid::Vector{UInt})
30+
ms, minvalid, maxvalid = matching_methods(atype, cache, max_methods, world)
31+
min_valid[1] = max(min_valid[1], minvalid)
32+
max_valid[1] = min(max_valid[1], maxvalid)
33+
return ms
34+
end
35+
1936
function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f), argtypes::Vector{Any}, @nospecialize(atype), sv::InferenceState,
20-
max_methods = InferenceParams(interp).MAX_METHODS)
37+
max_methods::Int = InferenceParams(interp).MAX_METHODS)
2138
atype_params = unwrap_unionall(atype).parameters
2239
ft = unwrap_unionall(atype_params[1]) # TODO: ccall jl_method_table_for here
2340
isa(ft, DataType) || return Any # the function being called is unknown. can't properly handle this backedge right now
@@ -42,22 +59,14 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
4259
splitsigs = switchtupleunion(atype)
4360
applicable = Any[]
4461
for sig_n in splitsigs
45-
(xapplicable, min_valid[1], max_valid[1]) =
46-
get!(sv.matching_methods_cache, sig_n) do
47-
ms = _methods_by_ftype(sig_n, max_methods,
48-
get_world_counter(interp), min_valid, max_valid)
49-
return (ms, min_valid[1], max_valid[1])
50-
end
62+
xapplicable = matching_methods(sig_n, sv.matching_methods_cache, max_methods,
63+
get_world_counter(interp), min_valid, max_valid)
5164
xapplicable === false && return Any
5265
append!(applicable, xapplicable)
5366
end
5467
else
55-
(applicable, min_valid[1], max_valid[1]) =
56-
get!(sv.matching_methods_cache, atype) do
57-
ms = _methods_by_ftype(atype, max_methods,
58-
get_world_counter(interp), min_valid, max_valid)
59-
return (ms, min_valid[1], max_valid[1])
60-
end
68+
applicable = matching_methods(atype, sv.matching_methods_cache, max_methods,
69+
get_world_counter(interp), min_valid, max_valid)
6170
if applicable === false
6271
# this means too many methods matched
6372
# (assume this will always be true, so we don't compute / update valid age in this case)
@@ -595,7 +604,7 @@ end
595604

596605
# do apply(af, fargs...), where af is a function value
597606
function abstract_apply(interp::AbstractInterpreter, @nospecialize(itft), @nospecialize(aft), aargtypes::Vector{Any}, vtypes::VarTable, sv::InferenceState,
598-
max_methods = InferenceParams(interp).MAX_METHODS)
607+
max_methods::Int = InferenceParams(interp).MAX_METHODS)
599608
aftw = widenconst(aft)
600609
if !isa(aft, Const) && (!isType(aftw) || has_free_typevars(aftw))
601610
if !isconcretetype(aftw) || (aftw <: Builtin)
@@ -694,7 +703,7 @@ function argtype_tail(argtypes::Vector{Any}, i::Int)
694703
end
695704

696705
# call where the function is known exactly
697-
function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f), fargs::Union{Nothing,Vector{Any}}, argtypes::Vector{Any}, vtypes::VarTable, sv::InferenceState, max_methods = InferenceParams(interp).MAX_METHODS)
706+
function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f), fargs::Union{Nothing,Vector{Any}}, argtypes::Vector{Any}, vtypes::VarTable, sv::InferenceState, max_methods::Int = InferenceParams(interp).MAX_METHODS)
698707
la = length(argtypes)
699708

700709
if isa(f, Builtin)
@@ -911,7 +920,7 @@ end
911920

912921
# call where the function is any lattice element
913922
function abstract_call(interp::AbstractInterpreter, fargs::Union{Nothing,Vector{Any}}, argtypes::Vector{Any},
914-
vtypes::VarTable, sv::InferenceState, max_methods = InferenceParams(interp).MAX_METHODS)
923+
vtypes::VarTable, sv::InferenceState, max_methods::Int = InferenceParams(interp).MAX_METHODS)
915924
#print("call ", e.args[1], argtypes, "\n\n")
916925
ft = argtypes[1]
917926
if isa(ft, Const)

base/compiler/ssair/inlining.jl

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,18 +1041,13 @@ function assemble_inline_todo!(ir::IRCode, sv::OptimizationState)
10411041
local fully_covered = true
10421042
for atype in splits
10431043
# Regular case: Retrieve matching methods from cache (or compute them)
1044-
(meth, min_valid, max_valid) = get(sv.matching_methods_cache, atype) do
1045-
# World age does not need to be taken into account in the cache
1046-
# because it is forwarded from type inference through `sv.params`
1047-
# in the case that the cache is nonempty, so it should be unchanged
1048-
# The max number of methods should be the same as in inference most
1049-
# of the time, and should not affect correctness otherwise.
1050-
min_val = UInt[typemin(UInt)]
1051-
max_val = UInt[typemax(UInt)]
1052-
ms = _methods_by_ftype(atype, sv.params.MAX_METHODS,
1053-
sv.world, min_val, max_val)
1054-
return (ms, min_val[1], max_val[1])
1055-
end
1044+
# World age does not need to be taken into account in the cache
1045+
# because it is forwarded from type inference through `sv.params`
1046+
# in the case that the cache is nonempty, so it should be unchanged
1047+
# The max number of methods should be the same as in inference most
1048+
# of the time, and should not affect correctness otherwise.
1049+
(meth, min_valid, max_valid) =
1050+
matching_methods(atype, sv.matching_methods_cache, sv.params.MAX_METHODS, sv.world)
10561051
if meth === false
10571052
# Too many applicable methods
10581053
too_many = true
@@ -1100,12 +1095,10 @@ function assemble_inline_todo!(ir::IRCode, sv::OptimizationState)
11001095
if signature_fully_covered && length(cases) == 0 && only_method isa Method
11011096
if length(splits) > 1
11021097
# get match information for a single overall match instead of union splits
1103-
meth = get(sv.matching_methods_cache, sig.atype) do
1104-
ms = _methods_by_ftype(sig.atype, sv.params.MAX_METHODS,
1105-
sv.world, UInt[typemin(UInt)], UInt[typemin(UInt)])
1106-
return ms
1107-
end
1098+
(meth, min_valid, max_valid) =
1099+
matching_methods(sig.atype, sv.matching_methods_cache, sv.params.MAX_METHODS, sv.world)
11081100
@assert length(meth) == 1
1101+
update_valid_age!(min_valid, max_valid, sv)
11091102
end
11101103
(metharg, methsp, method) = (meth[1][1]::Type, meth[1][2]::SimpleVector, meth[1][3]::Method)
11111104
fully_covered = true

0 commit comments

Comments
 (0)