Skip to content

Commit 5256d57

Browse files
aviateskpull[bot]
authored andcommitted
effects: taint overlay-ed method's :nonoverlayed effect bit (#51078)
1 parent 543c861 commit 5256d57

File tree

8 files changed

+46
-63
lines changed

8 files changed

+46
-63
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
1616
# At this point we are guaranteed to end up throwing on this path,
1717
# which is all that's required for :consistent-cy. Of course, we don't
1818
# know anything else about this statement.
19-
effects = Effects(; consistent=ALWAYS_TRUE, nonoverlayed=!isoverlayed(method_table(interp)))
19+
effects = Effects(; consistent=ALWAYS_TRUE)
2020
return CallMeta(Any, effects, NoCallInfo())
2121
end
2222

@@ -28,7 +28,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
2828
return CallMeta(Any, Effects(), NoCallInfo())
2929
end
3030

31-
(; valid_worlds, applicable, info, nonoverlayed) = matches
31+
(; valid_worlds, applicable, info) = matches
3232
update_valid_age!(sv, valid_worlds)
3333
napplicable = length(applicable)
3434
rettype = Bottom
@@ -39,7 +39,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
3939
const_results = Union{Nothing,ConstResult}[]
4040
multiple_matches = napplicable > 1
4141
fargs = arginfo.fargs
42-
all_effects = Effects(EFFECTS_TOTAL; nonoverlayed)
42+
all_effects = EFFECTS_TOTAL
4343

4444
𝕃ₚ = ipo_lattice(interp)
4545
for i in 1:napplicable
@@ -205,7 +205,6 @@ struct MethodMatches
205205
valid_worlds::WorldRange
206206
mt::MethodTable
207207
fullmatch::Bool
208-
nonoverlayed::Bool
209208
end
210209
any_ambig(info::MethodMatchInfo) = info.results.ambig
211210
any_ambig(m::MethodMatches) = any_ambig(m.info)
@@ -217,7 +216,6 @@ struct UnionSplitMethodMatches
217216
valid_worlds::WorldRange
218217
mts::Vector{MethodTable}
219218
fullmatches::Vector{Bool}
220-
nonoverlayed::Bool
221219
end
222220
any_ambig(m::UnionSplitMethodMatches) = any(any_ambig, m.info.matches)
223221

@@ -233,19 +231,16 @@ function find_matching_methods(𝕃::AbstractLattice,
233231
valid_worlds = WorldRange()
234232
mts = MethodTable[]
235233
fullmatches = Bool[]
236-
nonoverlayed = true
237234
for i in 1:length(split_argtypes)
238235
arg_n = split_argtypes[i]::Vector{Any}
239236
sig_n = argtypes_to_type(arg_n)
240237
mt = ccall(:jl_method_table_for, Any, (Any,), sig_n)
241238
mt === nothing && return FailedMethodMatch("Could not identify method table for call")
242239
mt = mt::MethodTable
243-
result = findall(sig_n, method_table; limit = max_methods)
244-
if result === nothing
240+
matches = findall(sig_n, method_table; limit = max_methods)
241+
if matches === nothing
245242
return FailedMethodMatch("For one of the union split cases, too many methods matched")
246243
end
247-
(; matches, overlayed) = result
248-
nonoverlayed &= !overlayed
249244
push!(infos, MethodMatchInfo(matches))
250245
for m in matches
251246
push!(applicable, m)
@@ -271,28 +266,25 @@ function find_matching_methods(𝕃::AbstractLattice,
271266
UnionSplitInfo(infos),
272267
valid_worlds,
273268
mts,
274-
fullmatches,
275-
nonoverlayed)
269+
fullmatches)
276270
else
277271
mt = ccall(:jl_method_table_for, Any, (Any,), atype)
278272
if mt === nothing
279273
return FailedMethodMatch("Could not identify method table for call")
280274
end
281275
mt = mt::MethodTable
282-
result = findall(atype, method_table; limit = max_methods)
283-
if result === nothing
276+
matches = findall(atype, method_table; limit = max_methods)
277+
if matches === nothing
284278
# this means too many methods matched
285279
# (assume this will always be true, so we don't compute / update valid age in this case)
286280
return FailedMethodMatch("Too many methods matched")
287281
end
288-
(; matches, overlayed) = result
289282
fullmatch = any(match::MethodMatch->match.fully_covers, matches)
290283
return MethodMatches(matches.matches,
291284
MethodMatchInfo(matches),
292285
matches.valid_worlds,
293286
mt,
294-
fullmatch,
295-
!overlayed)
287+
fullmatch)
296288
end
297289
end
298290

@@ -862,7 +854,7 @@ function concrete_eval_eligible(interp::AbstractInterpreter,
862854
mi = result.edge
863855
if mi !== nothing && is_foldable(effects)
864856
if f !== nothing && is_all_const_arg(arginfo, #=start=#2)
865-
if is_nonoverlayed(mi.def::Method) && (!isoverlayed(method_table(interp)) || is_nonoverlayed(effects))
857+
if is_nonoverlayed(interp) || is_nonoverlayed(effects)
866858
return :concrete_eval
867859
end
868860
# disable concrete-evaluation if this function call is tainted by some overlayed
@@ -1924,7 +1916,7 @@ function abstract_invoke(interp::AbstractInterpreter, (; fargs, argtypes)::ArgIn
19241916
lookupsig = rewrap_unionall(Tuple{ft, unwrapped.parameters...}, types)::Type
19251917
nargtype = Tuple{ft, nargtype.parameters...}
19261918
argtype = Tuple{ft, argtype.parameters...}
1927-
match, valid_worlds, overlayed = findsup(lookupsig, method_table(interp))
1919+
match, valid_worlds = findsup(lookupsig, method_table(interp))
19281920
match === nothing && return CallMeta(Any, Effects(), NoCallInfo())
19291921
update_valid_age!(sv, valid_worlds)
19301922
method = match.method
@@ -1955,7 +1947,6 @@ function abstract_invoke(interp::AbstractInterpreter, (; fargs, argtypes)::ArgIn
19551947
end
19561948
end
19571949
rt = from_interprocedural!(interp, rt, sv, arginfo, sig)
1958-
effects = Effects(effects; nonoverlayed = !overlayed)
19591950
info = InvokeCallInfo(match, const_result)
19601951
edge !== nothing && add_invoke_backedge!(sv, lookupsig, edge)
19611952
return CallMeta(rt, effects, info)

base/compiler/inferencestate.jl

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,11 @@ mutable struct InferenceState
296296
ipo_effects = Effects(ipo_effects; effect_free = ALWAYS_FALSE)
297297
end
298298

299-
restrict_abstract_call_sites = isa(linfo.def, Module)
299+
if def isa Method
300+
ipo_effects = Effects(ipo_effects; nonoverlayed=is_nonoverlayed(def))
301+
end
302+
303+
restrict_abstract_call_sites = isa(def, Module)
300304
@assert cache === :no || cache === :local || cache === :global
301305
cached = cache === :global
302306

@@ -314,6 +318,13 @@ mutable struct InferenceState
314318
end
315319
end
316320

321+
is_nonoverlayed(m::Method) = !isdefined(m, :external_mt)
322+
is_nonoverlayed(interp::AbstractInterpreter) = !isoverlayed(method_table(interp))
323+
isoverlayed(::MethodTableView) = error("unsatisfied MethodTableView interface")
324+
isoverlayed(::InternalMethodTable) = false
325+
isoverlayed(::OverlayMethodTable) = true
326+
isoverlayed(mt::CachedMethodTable) = isoverlayed(mt.table)
327+
317328
is_inferred(sv::InferenceState) = is_inferred(sv.result)
318329
is_inferred(result::InferenceResult) = result.result !== nothing
319330

base/compiler/methodtable.jl

Lines changed: 16 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@ function iterate(result::MethodLookupResult, args...)
1616
end
1717
getindex(result::MethodLookupResult, idx::Int) = getindex(result.matches, idx)::MethodMatch
1818

19-
struct MethodMatchResult
20-
matches::MethodLookupResult
21-
overlayed::Bool
22-
end
23-
2419
"""
2520
struct InternalMethodTable <: MethodTableView
2621
@@ -55,47 +50,42 @@ Overlays another method table view with an additional local fast path cache that
5550
can respond to repeated, identical queries faster than the original method table.
5651
"""
5752
struct CachedMethodTable{T<:MethodTableView} <: MethodTableView
58-
cache::IdDict{MethodMatchKey, Union{Nothing,MethodMatchResult}}
53+
cache::IdDict{MethodMatchKey, Union{Nothing,MethodLookupResult}}
5954
table::T
6055
end
61-
CachedMethodTable(table::T) where T = CachedMethodTable{T}(IdDict{MethodMatchKey, Union{Nothing,MethodMatchResult}}(), table)
56+
CachedMethodTable(table::T) where T = CachedMethodTable{T}(IdDict{MethodMatchKey, Union{Nothing,MethodLookupResult}}(), table)
6257

6358
"""
6459
findall(sig::Type, view::MethodTableView; limit::Int=-1) ->
65-
MethodMatchResult(matches::MethodLookupResult, overlayed::Bool) or nothing
60+
matches::MethodLookupResult or nothing
6661
6762
Find all methods in the given method table `view` that are applicable to the given signature `sig`.
6863
If no applicable methods are found, an empty result is returned.
6964
If the number of applicable methods exceeded the specified `limit`, `nothing` is returned.
7065
Note that the default setting `limit=-1` does not limit the number of applicable methods.
7166
`overlayed` indicates if any of the matching methods comes from an overlayed method table.
7267
"""
73-
function findall(@nospecialize(sig::Type), table::InternalMethodTable; limit::Int=-1)
74-
result = _findall(sig, nothing, table.world, limit)
75-
result === nothing && return nothing
76-
return MethodMatchResult(result, false)
77-
end
68+
findall(@nospecialize(sig::Type), table::InternalMethodTable; limit::Int=-1) =
69+
_findall(sig, nothing, table.world, limit)
7870

7971
function findall(@nospecialize(sig::Type), table::OverlayMethodTable; limit::Int=-1)
8072
result = _findall(sig, table.mt, table.world, limit)
8173
result === nothing && return nothing
8274
nr = length(result)
8375
if nr 1 && result[nr].fully_covers
8476
# no need to fall back to the internal method table
85-
return MethodMatchResult(result, true)
77+
return result
8678
end
8779
# fall back to the internal method table
8880
fallback_result = _findall(sig, nothing, table.world, limit)
8981
fallback_result === nothing && return nothing
9082
# merge the fallback match results with the internal method table
91-
return MethodMatchResult(
92-
MethodLookupResult(
93-
vcat(result.matches, fallback_result.matches),
94-
WorldRange(
95-
max(result.valid_worlds.min_world, fallback_result.valid_worlds.min_world),
96-
min(result.valid_worlds.max_world, fallback_result.valid_worlds.max_world)),
97-
result.ambig | fallback_result.ambig),
98-
!isempty(result))
83+
return MethodLookupResult(
84+
vcat(result.matches, fallback_result.matches),
85+
WorldRange(
86+
max(result.valid_worlds.min_world, fallback_result.valid_worlds.min_world),
87+
min(result.valid_worlds.max_world, fallback_result.valid_worlds.max_world)),
88+
result.ambig | fallback_result.ambig)
9989
end
10090

10191
function _findall(@nospecialize(sig::Type), mt::Union{Nothing,MethodTable}, world::UInt, limit::Int)
@@ -138,21 +128,19 @@ In both cases `nothing` is returned.
138128
139129
`overlayed` indicates if any of the matching methods comes from an overlayed method table.
140130
"""
141-
function findsup(@nospecialize(sig::Type), table::InternalMethodTable)
142-
return (_findsup(sig, nothing, table.world)..., false)
143-
end
131+
findsup(@nospecialize(sig::Type), table::InternalMethodTable) =
132+
_findsup(sig, nothing, table.world)
144133

145134
function findsup(@nospecialize(sig::Type), table::OverlayMethodTable)
146135
match, valid_worlds = _findsup(sig, table.mt, table.world)
147-
match !== nothing && return match, valid_worlds, true
136+
match !== nothing && return match, valid_worlds
148137
# fall back to the internal method table
149138
fallback_match, fallback_valid_worlds = _findsup(sig, nothing, table.world)
150139
return (
151140
fallback_match,
152141
WorldRange(
153142
max(valid_worlds.min_world, fallback_valid_worlds.min_world),
154-
min(valid_worlds.max_world, fallback_valid_worlds.max_world)),
155-
false)
143+
min(valid_worlds.max_world, fallback_valid_worlds.max_world)))
156144
end
157145

158146
function _findsup(@nospecialize(sig::Type), mt::Union{Nothing,MethodTable}, world::UInt)
@@ -166,10 +154,3 @@ end
166154

167155
# This query is not cached
168156
findsup(@nospecialize(sig::Type), table::CachedMethodTable) = findsup(sig, table.table)
169-
170-
isoverlayed(::MethodTableView) = error("unsatisfied MethodTableView interface")
171-
isoverlayed(::InternalMethodTable) = false
172-
isoverlayed(::OverlayMethodTable) = true
173-
isoverlayed(mt::CachedMethodTable) = isoverlayed(mt.table)
174-
isoverlayed(m::Method) = isdefined(m, :external_mt)
175-
is_nonoverlayed(m::Method) = !isoverlayed(m)

base/compiler/ssair/irinterp.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ function concrete_eval_invoke(interp::AbstractInterpreter,
1515
argtypes === nothing && return Pair{Any,Bool}(Bottom, false)
1616
effects = decode_effects(code.ipo_purity_bits)
1717
if (is_foldable(effects) && is_all_const_arg(argtypes, #=start=#1) &&
18-
is_nonoverlayed(effects) && is_nonoverlayed(mi.def::Method))
18+
(is_nonoverlayed(interp) || is_nonoverlayed(effects)))
1919
args = collect_const_args(argtypes, #=start=#1)
2020
value = let world = get_world_counter(interp)
2121
try

base/compiler/tfuncs.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2763,7 +2763,7 @@ function _hasmethod_tfunc(interp::AbstractInterpreter, argtypes::Vector{Any}, sv
27632763
if !isa(mt, MethodTable)
27642764
return CallMeta(Bool, EFFECTS_THROWS, NoCallInfo())
27652765
end
2766-
match, valid_worlds, overlayed = findsup(types, method_table(interp))
2766+
match, valid_worlds = findsup(types, method_table(interp))
27672767
update_valid_age!(sv, valid_worlds)
27682768
if match === nothing
27692769
rt = Const(false)

base/reflection.jl

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1633,13 +1633,12 @@ function infer_effects(@nospecialize(f), @nospecialize(types=default_tt(f));
16331633
Core.Compiler.ArgInfo(nothing, argtypes), rt)
16341634
end
16351635
tt = signature_type(f, types)
1636-
result = Core.Compiler.findall(tt, Core.Compiler.method_table(interp))
1637-
if result === nothing
1636+
matches = Core.Compiler.findall(tt, Core.Compiler.method_table(interp))
1637+
if matches === nothing
16381638
# unanalyzable call, i.e. the interpreter world might be newer than the world where
16391639
# the `f` is defined, return the unknown effects
16401640
return Core.Compiler.Effects()
16411641
end
1642-
(; matches) = result
16431642
effects = Core.Compiler.EFFECTS_TOTAL
16441643
if matches.ambig || !any(match::Core.MethodMatch->match.fully_covers, matches.matches)
16451644
# account for the fact that we may encounter a MethodError with a non-covered or ambiguous signature.

test/compiler/AbstractInterpreter.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ callstrange(::Float64) = strangesin(x)
5555
callstrange(::Nothing) = Core.compilerbarrier(:type, nothing) # trigger inference bail out
5656
callstrange_entry(x) = callstrange(x) # needs to be defined here because of world age
5757
let interp = MTOverlayInterp(Set{Any}())
58-
matches = Core.Compiler.findall(Tuple{typeof(callstrange),Any}, Core.Compiler.method_table(interp)).matches
58+
matches = Core.Compiler.findall(Tuple{typeof(callstrange),Any}, Core.Compiler.method_table(interp))
59+
@test matches !== nothing
5960
@test Core.Compiler.length(matches) == 2
6061
if Core.Compiler.getindex(matches, 1).method == which(callstrange, (Nothing,))
6162
@test Base.infer_effects(callstrange_entry, (Any,); interp) |> !Core.Compiler.is_nonoverlayed

test/compiler/datastructures.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ using Test
88
sig = Tuple{typeof(*), Any, Any}
99
result1 = Core.Compiler.findall(sig, table; limit=-1)
1010
result2 = Core.Compiler.findall(sig, table; limit=Core.Compiler.InferenceParams().max_methods)
11-
@test result1 !== nothing && !Core.Compiler.isempty(result1.matches)
11+
@test result1 !== nothing && !Core.Compiler.isempty(result1)
1212
@test result2 === nothing
1313
end
1414

0 commit comments

Comments
 (0)