Skip to content

Commit 92998f2

Browse files
authored
Add edge kind for access to non-explicit partitioned bindings (JuliaLang#57009)
Our binding partion invalidation code scans the original source for any GlobalRefs that need to be invalidated. However, this is not the only source of access to binding partitions. Various intrinsics (in particular the `*global` ones) also operate on bindings. Since these are not manifest in the source, we instead use the existing `edges` mechanism to give them forward edges. This PR only includes the basic info type, and validation in the replacement case. There's a bit more work to do there, but I'm waiting on JuliaLang#56499 for that part, precompilation in particular.
1 parent 0a07e0b commit 92998f2

File tree

3 files changed

+55
-48
lines changed

3 files changed

+55
-48
lines changed

src/abstractinterpretation.jl

Lines changed: 38 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2395,7 +2395,8 @@ function abstract_eval_getglobal(interp::AbstractInterpreter, sv::AbsIntState, s
23952395
if M isa Const && s isa Const
23962396
M, s = M.val, s.val
23972397
if M isa Module && s isa Symbol
2398-
return CallMeta(abstract_eval_globalref(interp, GlobalRef(M, s), saw_latestworld, sv), NoCallInfo())
2398+
(ret, bpart) = abstract_eval_globalref(interp, GlobalRef(M, s), saw_latestworld, sv)
2399+
return CallMeta(ret, bpart === nothing ? NoCallInfo() : GlobalAccessInfo(bpart))
23992400
end
24002401
return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
24012402
elseif !hasintersect(widenconst(M), Module) || !hasintersect(widenconst(s), Symbol)
@@ -2473,8 +2474,8 @@ function abstract_eval_setglobal!(interp::AbstractInterpreter, sv::AbsIntState,
24732474
if isa(M, Const) && isa(s, Const)
24742475
M, s = M.val, s.val
24752476
if M isa Module && s isa Symbol
2476-
rt, exct = global_assignment_rt_exct(interp, sv, saw_latestworld, GlobalRef(M, s), v)
2477-
return CallMeta(rt, exct, Effects(setglobal!_effects, nothrow=exct===Bottom), NoCallInfo())
2477+
(rt, exct), partition = global_assignment_rt_exct(interp, sv, saw_latestworld, GlobalRef(M, s), v)
2478+
return CallMeta(rt, exct, Effects(setglobal!_effects, nothrow=exct===Bottom), GlobalAccessInfo(partition))
24782479
end
24792480
return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
24802481
end
@@ -2512,15 +2513,15 @@ function abstract_eval_swapglobal!(interp::AbstractInterpreter, sv::AbsIntState,
25122513
scm = abstract_eval_setglobal!(interp, sv, saw_latestworld, M, s, v)
25132514
scm.rt === Bottom && return scm
25142515
gcm = abstract_eval_getglobal(interp, sv, saw_latestworld, M, s)
2515-
return CallMeta(gcm.rt, Union{scm.exct,gcm.exct}, merge_effects(scm.effects, gcm.effects), NoCallInfo())
2516+
return CallMeta(gcm.rt, Union{scm.exct,gcm.exct}, merge_effects(scm.effects, gcm.effects), scm.info)
25162517
end
25172518

25182519
function abstract_eval_swapglobal!(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool,
25192520
@nospecialize(M), @nospecialize(s), @nospecialize(v), @nospecialize(order))
25202521
scm = abstract_eval_setglobal!(interp, sv, saw_latestworld, M, s, v, order)
25212522
scm.rt === Bottom && return scm
25222523
gcm = abstract_eval_getglobal(interp, sv, saw_latestworld, M, s, order)
2523-
return CallMeta(gcm.rt, Union{scm.exct,gcm.exct}, merge_effects(scm.effects, gcm.effects), NoCallInfo())
2524+
return CallMeta(gcm.rt, Union{scm.exct,gcm.exct}, merge_effects(scm.effects, gcm.effects), scm.info)
25242525
end
25252526

25262527
function abstract_eval_swapglobal!(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, argtypes::Vector{Any})
@@ -2569,7 +2570,7 @@ function abstract_eval_replaceglobal!(interp::AbstractInterpreter, sv::AbsIntSta
25692570
end
25702571
exct = Union{rte.exct, global_assignment_binding_rt_exct(interp, partition, v)[2]}
25712572
effects = merge_effects(rte.effects, Effects(setglobal!_effects, nothrow=exct===Bottom))
2572-
sg = CallMeta(Any, exct, effects, NoCallInfo())
2573+
sg = CallMeta(Any, exct, effects, GlobalAccessInfo(partition))
25732574
else
25742575
sg = abstract_eval_setglobal!(interp, sv, saw_latestworld, M, s, v)
25752576
end
@@ -2937,7 +2938,8 @@ function abstract_eval_special_value(interp::AbstractInterpreter, @nospecialize(
29372938
return RTEffects(sv.ir.argtypes[e.n], Union{}, EFFECTS_TOTAL) # TODO frame_argtypes(sv)[e.n] and remove the assertion
29382939
end
29392940
elseif isa(e, GlobalRef)
2940-
return abstract_eval_globalref(interp, e, sstate.saw_latestworld, sv)
2941+
# No need for an edge since an explicit GlobalRef will be picked up by the source scan
2942+
return abstract_eval_globalref(interp, e, sstate.saw_latestworld, sv)[1]
29412943
end
29422944
if isa(e, QuoteNode)
29432945
e = e.value
@@ -3193,14 +3195,31 @@ function abstract_eval_isdefined_expr(interp::AbstractInterpreter, e::Expr, ssta
31933195
end
31943196
return RTEffects(rt, Union{}, EFFECTS_TOTAL)
31953197
end
3196-
return abstract_eval_isdefined(interp, sym, sstate.saw_latestworld, sv)
3198+
rt = Bool
3199+
effects = EFFECTS_TOTAL
3200+
exct = Union{}
3201+
if isexpr(sym, :static_parameter)
3202+
n = sym.args[1]::Int
3203+
if 1 <= n <= length(sv.sptypes)
3204+
sp = sv.sptypes[n]
3205+
if !sp.undef
3206+
rt = Const(true)
3207+
elseif sp.typ === Bottom
3208+
rt = Const(false)
3209+
end
3210+
end
3211+
else
3212+
effects = EFFECTS_UNKNOWN
3213+
exct = Any
3214+
end
3215+
return RTEffects(rt, exct, effects)
31973216
end
31983217

31993218
const generic_isdefinedglobal_effects = Effects(EFFECTS_TOTAL, consistent=ALWAYS_FALSE, nothrow=false)
32003219
function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, mod::Module, sym::Symbol, allow_import::Union{Bool, Nothing}, saw_latestworld::Bool, sv::AbsIntState)
32013220
rt = Bool
32023221
if saw_latestworld
3203-
return RTEffects(rt, Union{}, Effects(generic_isdefinedglobal_effects, nothrow=true))
3222+
return CallMeta(RTEffects(rt, Union{}, Effects(generic_isdefinedglobal_effects, nothrow=true)), NoCallInfo())
32043223
end
32053224

32063225
effects = EFFECTS_TOTAL
@@ -3222,7 +3241,7 @@ function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, mod::Module,
32223241
effects = Effects(generic_isdefinedglobal_effects, nothrow=true)
32233242
end
32243243
end
3225-
return RTEffects(rt, Union{}, effects)
3244+
return CallMeta(RTEffects(rt, Union{}, effects), GlobalAccessInfo(partition))
32263245
end
32273246

32283247
function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, @nospecialize(M), @nospecialize(s), @nospecialize(allow_import_arg), @nospecialize(order_arg), saw_latestworld::Bool, sv::AbsIntState)
@@ -3247,7 +3266,7 @@ function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, @nospecializ
32473266
if M isa Const && s isa Const
32483267
M, s = M.val, s.val
32493268
if M isa Module && s isa Symbol
3250-
return merge_exct(CallMeta(abstract_eval_isdefinedglobal(interp, M, s, allow_import, saw_latestworld, sv), NoCallInfo()), exct)
3269+
return merge_exct(abstract_eval_isdefinedglobal(interp, M, s, allow_import, saw_latestworld, sv), exct)
32513270
end
32523271
return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
32533272
elseif !hasintersect(widenconst(M), Module) || !hasintersect(widenconst(s), Symbol)
@@ -3258,26 +3277,6 @@ function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, @nospecializ
32583277
return CallMeta(Bool, Union{exct, TypeError, UndefVarError}, generic_isdefinedglobal_effects, NoCallInfo())
32593278
end
32603279

3261-
function abstract_eval_isdefined(interp::AbstractInterpreter, @nospecialize(sym), saw_latestworld::Bool, sv::AbsIntState)
3262-
rt = Bool
3263-
effects = EFFECTS_TOTAL
3264-
exct = Union{}
3265-
if isexpr(sym, :static_parameter)
3266-
n = sym.args[1]::Int
3267-
if 1 <= n <= length(sv.sptypes)
3268-
sp = sv.sptypes[n]
3269-
if !sp.undef
3270-
rt = Const(true)
3271-
elseif sp.typ === Bottom
3272-
rt = Const(false)
3273-
end
3274-
end
3275-
else
3276-
effects = EFFECTS_UNKNOWN
3277-
end
3278-
return RTEffects(rt, exct, effects)
3279-
end
3280-
32813280
function abstract_eval_throw_undef_if_not(interp::AbstractInterpreter, e::Expr, sstate::StatementState, sv::AbsIntState)
32823281
condt = abstract_eval_value(interp, e.args[2], sstate, sv)
32833282
condval = maybe_extract_const_bool(condt)
@@ -3533,26 +3532,29 @@ end
35333532

35343533
function abstract_eval_globalref(interp::AbstractInterpreter, g::GlobalRef, saw_latestworld::Bool, sv::AbsIntState)
35353534
if saw_latestworld
3536-
return RTEffects(Any, Any, generic_getglobal_effects)
3535+
return Pair{RTEffects, Union{Nothing, Core.BindingPartition}}(RTEffects(Any, Any, generic_getglobal_effects), nothing)
35373536
end
35383537
partition = abstract_eval_binding_partition!(interp, g, sv)
35393538
ret = abstract_eval_partition_load(interp, partition)
35403539
if ret.rt !== Union{} && ret.exct === UndefVarError && InferenceParams(interp).assume_bindings_static
35413540
if isdefined(g, :binding) && isdefined(g.binding, :value)
3542-
return RTEffects(ret.rt, Union{}, Effects(generic_getglobal_effects, nothrow=true))
3541+
ret = RTEffects(ret.rt, Union{}, Effects(generic_getglobal_effects, nothrow=true))
35433542
end
35443543
# We do not assume in general that assigned global bindings remain assigned.
35453544
# The existence of pkgimages allows them to revert in practice.
35463545
end
3547-
return ret
3546+
return Pair{RTEffects, Union{Nothing, Core.BindingPartition}}(ret, partition)
35483547
end
35493548

35503549
function global_assignment_rt_exct(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, g::GlobalRef, @nospecialize(newty))
35513550
if saw_latestworld
3552-
return Pair{Any,Any}(newty, Union{ErrorException, TypeError})
3551+
return Pair{Pair{Any,Any}, Union{Core.BindingPartition, Nothing}}(
3552+
Pair{Any,Any}(newty, Union{ErrorException, TypeError}), nothing)
35533553
end
35543554
partition = abstract_eval_binding_partition!(interp, g, sv)
3555-
return global_assignment_binding_rt_exct(interp, partition, newty)
3555+
return Pair{Pair{Any,Any}, Union{Core.BindingPartition, Nothing}}(
3556+
global_assignment_binding_rt_exct(interp, partition, newty),
3557+
partition)
35563558
end
35573559

35583560
function global_assignment_binding_rt_exct(interp::AbstractInterpreter, partition::Core.BindingPartition, @nospecialize(newty))
@@ -3573,18 +3575,6 @@ function global_assignment_binding_rt_exct(interp::AbstractInterpreter, partitio
35733575
return Pair{Any,Any}(newty, Bottom)
35743576
end
35753577

3576-
function handle_global_assignment!(interp::AbstractInterpreter, frame::InferenceState, saw_latestworld::Bool, lhs::GlobalRef, @nospecialize(newty))
3577-
effect_free = ALWAYS_FALSE
3578-
nothrow = global_assignment_rt_exct(interp, frame, saw_latestworld, lhs, ignorelimited(newty))[2] === Union{}
3579-
inaccessiblememonly = ALWAYS_FALSE
3580-
if !nothrow
3581-
sub_curr_ssaflag!(frame, IR_FLAG_NOTHROW)
3582-
end
3583-
sub_curr_ssaflag!(frame, IR_FLAG_EFFECT_FREE)
3584-
merge_effects!(interp, frame, Effects(EFFECTS_TOTAL; effect_free, nothrow, inaccessiblememonly))
3585-
return nothing
3586-
end
3587-
35883578
abstract_eval_ssavalue(s::SSAValue, sv::InferenceState) = abstract_eval_ssavalue(s, sv.ssavaluetypes)
35893579

35903580
function abstract_eval_ssavalue(s::SSAValue, ssavaluetypes::Vector{Any})

src/stmtinfo.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,4 +481,18 @@ end
481481
add_edges_impl(edges::Vector{Any}, info::VirtualMethodMatchInfo) =
482482
_add_edges_impl(edges, info.info, #=mi_edge=#true)
483483

484+
"""
485+
info::GlobalAccessInfo <: CallInfo
486+
487+
Represents access to a global through runtime reflection, rather than as a manifest
488+
`GlobalRef` in the source code. Used for builtins (getglobal/setglobal/etc.) that
489+
perform such accesses.
490+
"""
491+
struct GlobalAccessInfo <: CallInfo
492+
bpart::Core.BindingPartition
493+
end
494+
GlobalAccessInfo(::Nothing) = NoCallInfo()
495+
add_edges_impl(edges::Vector{Any}, info::GlobalAccessInfo) =
496+
push!(edges, info.bpart)
497+
484498
@specialize

src/typeinfer.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,9 @@ function store_backedges(caller::CodeInstance, edges::SimpleVector)
544544
# ignore `Method`-edges (from e.g. failed `abstract_call_method`)
545545
i += 1
546546
continue
547+
elseif isa(item, Core.BindingPartition)
548+
i += 1
549+
continue
547550
end
548551
if isa(item, CodeInstance)
549552
item = item.def

0 commit comments

Comments
 (0)