Skip to content

Commit f782430

Browse files
authored
effects: change the overlayed::Bool property to nonoverlayed::Bool (JuliaLang#44786)
The current naming of `overlayed` is a bit confusing since `overlayed === true`, which is the conservative default value, actually means "it _may_ be overlayed" while `overlayed === false` means "this is absolutely not overlayed". I think it should be named as `nonoverlayed`, and then a query name like `is_nonoverlayed` would be more sensible than the alternative `is_overlayed`, which actually should be something like `can_be_overlayed`.
1 parent 18a2031 commit f782430

File tree

7 files changed

+77
-83
lines changed

7 files changed

+77
-83
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 39 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -47,25 +47,23 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
4747
# function has not seen any side effects, we would like to make sure there
4848
# aren't any in the throw block either to enable other optimizations.
4949
add_remark!(interp, sv, "Skipped call in throw block")
50-
overlayed = true
51-
if isoverlayed(method_table(interp))
52-
if !sv.ipo_effects.overlayed
53-
# as we may want to concrete-evaluate this frame in cases when there are
54-
# no overlayed calls, try an additional effort now to check if this call
55-
# isn't overlayed rather than just handling it conservatively
56-
matches = find_matching_methods(arginfo.argtypes, atype, method_table(interp),
57-
InferenceParams(interp).MAX_UNION_SPLITTING, max_methods)
58-
if !isa(matches, FailedMethodMatch)
59-
overlayed = matches.overlayed
60-
end
50+
nonoverlayed = false
51+
if isoverlayed(method_table(interp)) && sv.ipo_effects.nonoverlayed
52+
# as we may want to concrete-evaluate this frame in cases when there are
53+
# no overlayed calls, try an additional effort now to check if this call
54+
# isn't overlayed rather than just handling it conservatively
55+
matches = find_matching_methods(arginfo.argtypes, atype, method_table(interp),
56+
InferenceParams(interp).MAX_UNION_SPLITTING, max_methods)
57+
if !isa(matches, FailedMethodMatch)
58+
nonoverlayed = matches.nonoverlayed
6159
end
6260
else
63-
overlayed = false
61+
nonoverlayed = true
6462
end
6563
# At this point we are guaranteed to end up throwing on this path,
6664
# which is all that's required for :consistent-cy. Of course, we don't
6765
# know anything else about this statement.
68-
tristate_merge!(sv, Effects(; consistent=ALWAYS_TRUE, overlayed))
66+
tristate_merge!(sv, Effects(; consistent=ALWAYS_TRUE, nonoverlayed))
6967
return CallMeta(Any, false)
7068
end
7169

@@ -88,11 +86,11 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
8886
any_const_result = false
8987
const_results = Union{InferenceResult,Nothing,ConstResult}[]
9088
multiple_matches = napplicable > 1
91-
if matches.overlayed
89+
if !matches.nonoverlayed
9290
# currently we don't have a good way to execute the overlayed method definition,
9391
# so we should give up pure/concrete eval when any of the matched methods is overlayed
9492
f = nothing
95-
tristate_merge!(sv, Effects(EFFECTS_TOTAL; overlayed=true))
93+
tristate_merge!(sv, Effects(EFFECTS_TOTAL; nonoverlayed=false))
9694
end
9795

9896
val = pure_eval_call(interp, f, applicable, arginfo, sv)
@@ -212,7 +210,9 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
212210
end
213211

214212
if seen != napplicable
215-
tristate_merge!(sv, Effects(; overlayed=false)) # already accounted for method overlay above
213+
# there may be unanalyzed effects within unseen dispatch candidate,
214+
# but we can still ignore nonoverlayed effect here since we already accounted for it
215+
tristate_merge!(sv, EFFECTS_UNKNOWN)
216216
elseif isa(matches, MethodMatches) ? (!matches.fullmatch || any_ambig(matches)) :
217217
(!_all(b->b, matches.fullmatches) || any_ambig(matches))
218218
# Account for the fact that we may encounter a MethodError with a non-covered or ambiguous signature.
@@ -251,7 +251,7 @@ struct MethodMatches
251251
valid_worlds::WorldRange
252252
mt::Core.MethodTable
253253
fullmatch::Bool
254-
overlayed::Bool
254+
nonoverlayed::Bool
255255
end
256256
any_ambig(info::MethodMatchInfo) = info.results.ambig
257257
any_ambig(m::MethodMatches) = any_ambig(m.info)
@@ -263,7 +263,7 @@ struct UnionSplitMethodMatches
263263
valid_worlds::WorldRange
264264
mts::Vector{Core.MethodTable}
265265
fullmatches::Vector{Bool}
266-
overlayed::Bool
266+
nonoverlayed::Bool
267267
end
268268
any_ambig(m::UnionSplitMethodMatches) = _any(any_ambig, m.info.matches)
269269

@@ -278,7 +278,7 @@ function find_matching_methods(argtypes::Vector{Any}, @nospecialize(atype), meth
278278
valid_worlds = WorldRange()
279279
mts = Core.MethodTable[]
280280
fullmatches = Bool[]
281-
overlayed = false
281+
nonoverlayed = true
282282
for i in 1:length(split_argtypes)
283283
arg_n = split_argtypes[i]::Vector{Any}
284284
sig_n = argtypes_to_type(arg_n)
@@ -289,8 +289,8 @@ function find_matching_methods(argtypes::Vector{Any}, @nospecialize(atype), meth
289289
if result === missing
290290
return FailedMethodMatch("For one of the union split cases, too many methods matched")
291291
end
292-
matches, overlayedᵢ = result
293-
overlayed |= overlayedᵢ
292+
matches, overlayed = result
293+
nonoverlayed &= !overlayed
294294
push!(infos, MethodMatchInfo(matches))
295295
for m in matches
296296
push!(applicable, m)
@@ -317,7 +317,7 @@ function find_matching_methods(argtypes::Vector{Any}, @nospecialize(atype), meth
317317
valid_worlds,
318318
mts,
319319
fullmatches,
320-
overlayed)
320+
nonoverlayed)
321321
else
322322
mt = ccall(:jl_method_table_for, Any, (Any,), atype)
323323
if mt === nothing
@@ -337,7 +337,7 @@ function find_matching_methods(argtypes::Vector{Any}, @nospecialize(atype), meth
337337
matches.valid_worlds,
338338
mt,
339339
fullmatch,
340-
overlayed)
340+
!overlayed)
341341
end
342342
end
343343

@@ -712,7 +712,7 @@ function concrete_eval_eligible(interp::AbstractInterpreter,
712712
@nospecialize(f), result::MethodCallResult, arginfo::ArgInfo, sv::InferenceState)
713713
# disable concrete-evaluation since this function call is tainted by some overlayed
714714
# method and currently there is no direct way to execute overlayed methods
715-
isoverlayed(method_table(interp)) && result.edge_effects.overlayed && return false
715+
isoverlayed(method_table(interp)) && !result.edge_effects.nonoverlayed && return false
716716
return f !== nothing &&
717717
result.edge !== nothing &&
718718
is_total_or_error(result.edge_effects) &&
@@ -1500,13 +1500,13 @@ end
15001500
function abstract_invoke(interp::AbstractInterpreter, (; fargs, argtypes)::ArgInfo, sv::InferenceState)
15011501
ft′ = argtype_by_index(argtypes, 2)
15021502
ft = widenconst(ft′)
1503-
ft === Bottom && return CallMeta(Bottom, false), EFFECTS_THROWN
1503+
ft === Bottom && return CallMeta(Bottom, false), EFFECTS_THROWS
15041504
(types, isexact, isconcrete, istype) = instanceof_tfunc(argtype_by_index(argtypes, 3))
1505-
types === Bottom && return CallMeta(Bottom, false), EFFECTS_THROWN
1505+
types === Bottom && return CallMeta(Bottom, false), EFFECTS_THROWS
15061506
isexact || return CallMeta(Any, false), Effects()
15071507
argtype = argtypes_to_type(argtype_tail(argtypes, 4))
15081508
nargtype = typeintersect(types, argtype)
1509-
nargtype === Bottom && return CallMeta(Bottom, false), EFFECTS_THROWN
1509+
nargtype === Bottom && return CallMeta(Bottom, false), EFFECTS_THROWS
15101510
nargtype isa DataType || return CallMeta(Any, false), Effects() # other cases are not implemented below
15111511
isdispatchelem(ft) || return CallMeta(Any, false), Effects() # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below
15121512
ft = ft::DataType
@@ -1540,6 +1540,7 @@ function abstract_invoke(interp::AbstractInterpreter, (; fargs, argtypes)::ArgIn
15401540
(; rt, effects, const_result) = const_call_result
15411541
end
15421542
end
1543+
effects = Effects(effects; nonoverlayed=!overlayed)
15431544
return CallMeta(from_interprocedural!(rt, sv, arginfo, sig), InvokeCallInfo(match, const_result)), effects
15441545
end
15451546

@@ -1585,12 +1586,12 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
15851586
end
15861587
end
15871588
end
1588-
tristate_merge!(sv, Effects(; overlayed=false)) # TODO
1589+
tristate_merge!(sv, EFFECTS_UNKNOWN) # TODO
15891590
return CallMeta(Any, false)
15901591
elseif f === TypeVar
15911592
# Manually look through the definition of TypeVar to
15921593
# make sure to be able to get `PartialTypeVar`s out.
1593-
tristate_merge!(sv, Effects(; overlayed=false)) # TODO
1594+
tristate_merge!(sv, EFFECTS_UNKNOWN) # TODO
15941595
(la < 2 || la > 4) && return CallMeta(Union{}, false)
15951596
n = argtypes[2]
15961597
ub_var = Const(Any)
@@ -1603,17 +1604,17 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
16031604
end
16041605
return CallMeta(typevar_tfunc(n, lb_var, ub_var), false)
16051606
elseif f === UnionAll
1606-
tristate_merge!(sv, Effects(; overlayed=false)) # TODO
1607+
tristate_merge!(sv, EFFECTS_UNKNOWN) # TODO
16071608
return CallMeta(abstract_call_unionall(argtypes), false)
16081609
elseif f === Tuple && la == 2
1609-
tristate_merge!(sv, Effects(; overlayed=false)) # TODO
1610+
tristate_merge!(sv, EFFECTS_UNKNOWN) # TODO
16101611
aty = argtypes[2]
16111612
ty = isvarargtype(aty) ? unwrapva(aty) : widenconst(aty)
16121613
if !isconcretetype(ty)
16131614
return CallMeta(Tuple, false)
16141615
end
16151616
elseif is_return_type(f)
1616-
tristate_merge!(sv, Effects(; overlayed=false)) # TODO
1617+
tristate_merge!(sv, EFFECTS_UNKNOWN) # TODO
16171618
return return_type_tfunc(interp, argtypes, sv)
16181619
elseif la == 2 && istopfunction(f, :!)
16191620
# handle Conditional propagation through !Bool
@@ -1956,21 +1957,21 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
19561957
effects.effect_free ? ALWAYS_TRUE : TRISTATE_UNKNOWN,
19571958
effects.nothrow ? ALWAYS_TRUE : TRISTATE_UNKNOWN,
19581959
effects.terminates_globally ? ALWAYS_TRUE : TRISTATE_UNKNOWN,
1959-
#=overlayed=#false
1960+
#=nonoverlayed=#true
19601961
))
19611962
else
1962-
tristate_merge!(sv, Effects(; overlayed=false))
1963+
tristate_merge!(sv, EFFECTS_UNKNOWN)
19631964
end
19641965
elseif ehead === :cfunction
1965-
tristate_merge!(sv, Effects(; overlayed=false))
1966+
tristate_merge!(sv, EFFECTS_UNKNOWN)
19661967
t = e.args[1]
19671968
isa(t, Type) || (t = Any)
19681969
abstract_eval_cfunction(interp, e, vtypes, sv)
19691970
elseif ehead === :method
1970-
tristate_merge!(sv, Effects(; overlayed=false))
1971+
tristate_merge!(sv, EFFECTS_UNKNOWN)
19711972
t = (length(e.args) == 1) ? Any : Nothing
19721973
elseif ehead === :copyast
1973-
tristate_merge!(sv, Effects(; overlayed=false))
1974+
tristate_merge!(sv, EFFECTS_UNKNOWN)
19741975
t = abstract_eval_value(interp, e.args[1], vtypes, sv)
19751976
if t isa Const && t.val isa Expr
19761977
# `copyast` makes copies of Exprs
@@ -2283,7 +2284,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
22832284
effect_free=ALWAYS_FALSE,
22842285
nothrow=TRISTATE_UNKNOWN))
22852286
elseif !isa(lhs, SSAValue)
2286-
tristate_merge!(frame, Effects(; overlayed=false))
2287+
tristate_merge!(frame, EFFECTS_UNKNOWN)
22872288
end
22882289
elseif hd === :method
22892290
stmt = stmt::Expr

base/compiler/inferencestate.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ mutable struct InferenceState
198198
#=parent=#nothing,
199199
#=cached=#cache === :global,
200200
#=inferred=#false, #=dont_work_on_me=#false, #=restrict_abstract_call_sites=# isa(linfo.def, Module),
201-
#=ipo_effects=#Effects(consistent, ALWAYS_TRUE, ALWAYS_TRUE, ALWAYS_TRUE, false, inbounds_taints_consistency),
201+
#=ipo_effects=#Effects(EFFECTS_TOTAL; consistent, inbounds_taints_consistency),
202202
interp)
203203
result.result = frame
204204
cache !== :no && push!(get_inference_cache(interp), result)

base/compiler/methodtable.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ getindex(result::MethodLookupResult, idx::Int) = getindex(result.matches, idx)::
4646
Find all methods in the given method table `view` that are applicable to the given signature `sig`.
4747
If no applicable methods are found, an empty result is returned.
4848
If the number of applicable methods exceeded the specified limit, `missing` is returned.
49-
`overlayed` indicates if any matching method is defined in an overlayed method table.
49+
`overlayed` indicates if any of the matching methods comes from an overlayed method table.
5050
"""
5151
function findall(@nospecialize(sig::Type), table::InternalMethodTable; limit::Int=Int(typemax(Int32)))
5252
result = _findall(sig, nothing, table.world, limit)
@@ -101,23 +101,23 @@ It is possible that no method is an upper bound of `sig`, or
101101
it is possible that among the upper bounds, there is no least element.
102102
In both cases `nothing` is returned.
103103
104-
`overlayed` indicates if the matching method is defined in an overlayed method table.
104+
`overlayed` indicates if any of the matching methods comes from an overlayed method table.
105105
"""
106106
function findsup(@nospecialize(sig::Type), table::InternalMethodTable)
107-
return (_findsup(sig, nothing, table.world)..., false)
107+
return (_findsup(sig, nothing, table.world)..., true)
108108
end
109109

110110
function findsup(@nospecialize(sig::Type), table::OverlayMethodTable)
111111
match, valid_worlds = _findsup(sig, table.mt, table.world)
112-
match !== nothing && return match, valid_worlds, true
112+
match !== nothing && return match, valid_worlds, false
113113
# fall back to the internal method table
114114
fallback_match, fallback_valid_worlds = _findsup(sig, nothing, table.world)
115115
return (
116116
fallback_match,
117117
WorldRange(
118118
max(valid_worlds.min_world, fallback_valid_worlds.min_world),
119119
min(valid_worlds.max_world, fallback_valid_worlds.max_world)),
120-
false)
120+
true)
121121
end
122122

123123
function _findsup(@nospecialize(sig::Type), mt::Union{Nothing,Core.MethodTable}, world::UInt)

base/compiler/ssair/show.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -803,7 +803,7 @@ function Base.show(io::IO, e::Core.Compiler.Effects)
803803
print(io, ',')
804804
printstyled(io, string(tristate_letter(e.terminates), 't'); color=tristate_color(e.terminates))
805805
print(io, ')')
806-
e.overlayed && printstyled(io, ''; color=:red)
806+
e.nonoverlayed || printstyled(io, ''; color=:red)
807807
end
808808

809809
@specialize

base/compiler/tfuncs.jl

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1795,11 +1795,11 @@ function builtin_effects(f::Builtin, argtypes::Vector{Any}, rt)
17951795
if (f === Core.getfield || f === Core.isdefined) && length(argtypes) >= 3
17961796
# consistent if the argtype is immutable
17971797
if isvarargtype(argtypes[2])
1798-
return Effects(; effect_free=ALWAYS_TRUE, terminates=ALWAYS_TRUE, overlayed=false)
1798+
return Effects(; effect_free=ALWAYS_TRUE, terminates=ALWAYS_TRUE, nonoverlayed=true)
17991799
end
18001800
s = widenconst(argtypes[2])
18011801
if isType(s) || !isa(s, DataType) || isabstracttype(s)
1802-
return Effects(; effect_free=ALWAYS_TRUE, terminates=ALWAYS_TRUE, overlayed=false)
1802+
return Effects(; effect_free=ALWAYS_TRUE, terminates=ALWAYS_TRUE, nonoverlayed=true)
18031803
end
18041804
s = s::DataType
18051805
ipo_consistent = !ismutabletype(s)
@@ -1828,13 +1828,10 @@ function builtin_effects(f::Builtin, argtypes::Vector{Any}, rt)
18281828
nothrow = isvarargtype(argtypes[end]) ? false : builtin_nothrow(f, argtypes[2:end], rt)
18291829
end
18301830

1831-
return Effects(
1832-
ipo_consistent ? ALWAYS_TRUE : ALWAYS_FALSE,
1833-
effect_free ? ALWAYS_TRUE : ALWAYS_FALSE,
1834-
nothrow ? ALWAYS_TRUE : TRISTATE_UNKNOWN,
1835-
#=terminates=#ALWAYS_TRUE,
1836-
#=overlayed=#false,
1837-
)
1831+
return Effects(EFFECTS_TOTAL;
1832+
consistent = ipo_consistent ? ALWAYS_TRUE : ALWAYS_FALSE,
1833+
effect_free = effect_free ? ALWAYS_TRUE : ALWAYS_FALSE,
1834+
nothrow = nothrow ? ALWAYS_TRUE : TRISTATE_UNKNOWN)
18381835
end
18391836

18401837
function builtin_nothrow(@nospecialize(f), argtypes::Array{Any, 1}, @nospecialize(rt))
@@ -2000,24 +1997,19 @@ function intrinsic_effects(f::IntrinsicFunction, argtypes::Vector{Any})
20001997
return Effects()
20011998
end
20021999

2003-
ipo_consistent = !(f === Intrinsics.pointerref || # this one is volatile
2004-
f === Intrinsics.arraylen || # this one is volatile
2000+
ipo_consistent = !(
2001+
f === Intrinsics.pointerref || # this one is volatile
2002+
f === Intrinsics.arraylen || # this one is volatile
20052003
f === Intrinsics.sqrt_llvm_fast || # this one may differ at runtime (by a few ulps)
2006-
f === Intrinsics.have_fma || # this one depends on the runtime environment
2007-
f === Intrinsics.cglobal) # cglobal lookup answer changes at runtime
2008-
2004+
f === Intrinsics.have_fma || # this one depends on the runtime environment
2005+
f === Intrinsics.cglobal) # cglobal lookup answer changes at runtime
20092006
effect_free = !(f === Intrinsics.pointerset)
2007+
nothrow = !isvarargtype(argtypes[end]) && intrinsic_nothrow(f, argtypes[2:end])
20102008

2011-
nothrow = isvarargtype(argtypes[end]) ? false :
2012-
intrinsic_nothrow(f, argtypes[2:end])
2013-
2014-
return Effects(
2015-
ipo_consistent ? ALWAYS_TRUE : ALWAYS_FALSE,
2016-
effect_free ? ALWAYS_TRUE : ALWAYS_FALSE,
2017-
nothrow ? ALWAYS_TRUE : TRISTATE_UNKNOWN,
2018-
#=terminates=#ALWAYS_TRUE,
2019-
#=overlayed=#false,
2020-
)
2009+
return Effects(EFFECTS_TOTAL;
2010+
consistent = ipo_consistent ? ALWAYS_TRUE : ALWAYS_FALSE,
2011+
effect_free = effect_free ? ALWAYS_TRUE : ALWAYS_FALSE,
2012+
nothrow = nothrow ? ALWAYS_TRUE : TRISTATE_UNKNOWN)
20212013
end
20222014

20232015
# TODO: this function is a very buggy and poor model of the return_type function

0 commit comments

Comments
 (0)