Skip to content

Commit e41d7a7

Browse files
authored
bpart: Start tracking backedges for bindings (JuliaLang#57213)
This PR adds limited backedge support for Bindings. There are two classes of bindings that get backedges: 1. Cross-module `GlobalRef` bindings (new in this PR) 2. Any globals accesses through intrinsics (i.e. those with forward edges from JuliaLang#57009) This is a time/space trade-off for invalidation. As a result of the first category, invalidating a binding now only needs to scan all the methods defined in the same module as the binding. At the same time, it is anticipated that most binding references are to bindings in the same module, keeping the list of bindings that need explicit (back)edges small.
1 parent cc6e1f0 commit e41d7a7

File tree

7 files changed

+30
-16
lines changed

7 files changed

+30
-16
lines changed

src/Compiler.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ using Base: @_foldable_meta, @_gc_preserve_begin, @_gc_preserve_end, @nospeciali
6767
partition_restriction, quoted, rename_unionall, rewrap_unionall, specialize_method,
6868
structdiff, tls_world_age, unconstrain_vararg_length, unionlen, uniontype_layout,
6969
uniontypes, unsafe_convert, unwrap_unionall, unwrapva, vect, widen_diagonal,
70-
_uncompressed_ir
70+
_uncompressed_ir, maybe_add_binding_backedge!
7171
using Base.Order
7272

7373
import Base: ==, _topmod, append!, convert, copy, copy!, findall, first, get, get!,

src/abstractinterpretation.jl

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(fun
208208
end
209209
if const_edge !== nothing
210210
edge = const_edge
211+
update_valid_age!(sv, world_range(const_edge))
211212
end
212213
end
213214

@@ -2330,6 +2331,7 @@ function abstract_invoke(interp::AbstractInterpreter, arginfo::ArgInfo, si::Stmt
23302331
end
23312332
if const_edge !== nothing
23322333
edge = const_edge
2334+
update_valid_age!(sv, world_range(const_edge))
23332335
end
23342336
end
23352337
rt = from_interprocedural!(interp, rt, sv, arginfo′, sig)
@@ -2396,8 +2398,9 @@ function abstract_eval_getglobal(interp::AbstractInterpreter, sv::AbsIntState, s
23962398
if M isa Const && s isa Const
23972399
M, s = M.val, s.val
23982400
if M isa Module && s isa Symbol
2399-
(ret, bpart) = abstract_eval_globalref(interp, GlobalRef(M, s), saw_latestworld, sv)
2400-
return CallMeta(ret, bpart === nothing ? NoCallInfo() : GlobalAccessInfo(bpart))
2401+
gr = GlobalRef(M, s)
2402+
(ret, bpart) = abstract_eval_globalref(interp, gr, saw_latestworld, sv)
2403+
return CallMeta(ret, bpart === nothing ? NoCallInfo() : GlobalAccessInfo(convert(Core.Binding, gr), bpart))
24012404
end
24022405
return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
24032406
elseif !hasintersect(widenconst(M), Module) || !hasintersect(widenconst(s), Symbol)
@@ -2475,8 +2478,9 @@ function abstract_eval_setglobal!(interp::AbstractInterpreter, sv::AbsIntState,
24752478
if isa(M, Const) && isa(s, Const)
24762479
M, s = M.val, s.val
24772480
if M isa Module && s isa Symbol
2478-
(rt, exct), partition = global_assignment_rt_exct(interp, sv, saw_latestworld, GlobalRef(M, s), v)
2479-
return CallMeta(rt, exct, Effects(setglobal!_effects, nothrow=exct===Bottom), GlobalAccessInfo(partition))
2481+
gr = GlobalRef(M, s)
2482+
(rt, exct), partition = global_assignment_rt_exct(interp, sv, saw_latestworld, gr, v)
2483+
return CallMeta(rt, exct, Effects(setglobal!_effects, nothrow=exct===Bottom), GlobalAccessInfo(convert(Core.Binding, gr), partition))
24802484
end
24812485
return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
24822486
end
@@ -2564,14 +2568,15 @@ function abstract_eval_replaceglobal!(interp::AbstractInterpreter, sv::AbsIntSta
25642568
M, s = M.val, s.val
25652569
M isa Module || return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
25662570
s isa Symbol || return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
2567-
partition = abstract_eval_binding_partition!(interp, GlobalRef(M, s), sv)
2571+
gr = GlobalRef(M, s)
2572+
partition = abstract_eval_binding_partition!(interp, gr, sv)
25682573
rte = abstract_eval_partition_load(interp, partition)
25692574
if binding_kind(partition) == BINDING_KIND_GLOBAL
25702575
T = partition_restriction(partition)
25712576
end
25722577
exct = Union{rte.exct, global_assignment_binding_rt_exct(interp, partition, v)[2]}
25732578
effects = merge_effects(rte.effects, Effects(setglobal!_effects, nothrow=exct===Bottom))
2574-
sg = CallMeta(Any, exct, effects, GlobalAccessInfo(partition))
2579+
sg = CallMeta(Any, exct, effects, GlobalAccessInfo(convert(Core.Binding, gr), partition))
25752580
else
25762581
sg = abstract_eval_setglobal!(interp, sv, saw_latestworld, M, s, v)
25772582
end
@@ -2791,6 +2796,7 @@ function abstract_call_opaque_closure(interp::AbstractInterpreter,
27912796
end
27922797
if const_edge !== nothing
27932798
edge = const_edge
2799+
update_valid_age!(sv, world_range(const_edge))
27942800
end
27952801
end
27962802
end
@@ -3225,7 +3231,8 @@ function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, mod::Module,
32253231
end
32263232

32273233
effects = EFFECTS_TOTAL
3228-
partition = lookup_binding_partition!(interp, GlobalRef(mod, sym), sv)
3234+
gr = GlobalRef(mod, sym)
3235+
partition = lookup_binding_partition!(interp, gr, sv)
32293236
if allow_import !== true && is_some_imported(binding_kind(partition))
32303237
if allow_import === false
32313238
rt = Const(false)
@@ -3243,7 +3250,7 @@ function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, mod::Module,
32433250
effects = Effects(generic_isdefinedglobal_effects, nothrow=true)
32443251
end
32453252
end
3246-
return CallMeta(RTEffects(rt, Union{}, effects), GlobalAccessInfo(partition))
3253+
return CallMeta(RTEffects(rt, Union{}, effects), GlobalAccessInfo(convert(Core.Binding, gr), partition))
32473254
end
32483255

32493256
function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, @nospecialize(M), @nospecialize(s), @nospecialize(allow_import_arg), @nospecialize(order_arg), saw_latestworld::Bool, sv::AbsIntState)
@@ -3454,6 +3461,7 @@ end
34543461

34553462
world_range(ir::IRCode) = ir.valid_worlds
34563463
world_range(ci::CodeInfo) = WorldRange(ci.min_world, ci.max_world)
3464+
world_range(ci::CodeInstance) = WorldRange(ci.min_world, ci.max_world)
34573465
world_range(compact::IncrementalCompact) = world_range(compact.ir)
34583466

34593467
function force_binding_resolution!(g::GlobalRef, world::UInt)

src/bootstrap.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,6 @@ function activate!(; reflection=true, codegen=false)
9191
Base.REFLECTION_COMPILER[] = Compiler
9292
end
9393
if codegen
94-
activate_codegen!()
94+
bootstrap!()
9595
end
9696
end

src/ssair/verify.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,10 @@ function check_op(ir::IRCode, domtree::DomTree, @nospecialize(op), use_bb::Int,
6767
imported_binding = partition_restriction(bpart)::Core.Binding
6868
bpart = lookup_binding_partition(min_world(ir.valid_worlds), imported_binding)
6969
end
70-
if !is_defined_const_binding(binding_kind(bpart)) || (bpart.max_world < max_world(ir.valid_worlds))
70+
if (!is_defined_const_binding(binding_kind(bpart)) || (bpart.max_world < max_world(ir.valid_worlds))) &&
71+
(op.mod !== Core) && (op.mod !== Base)
72+
# Core and Base are excluded because the frontend uses them for intrinsics, etc.
73+
# TODO: Decide which way to go with these.
7174
@verify_error "Unbound or partitioned GlobalRef not allowed in value position"
7275
raise_error()
7376
end

src/stmtinfo.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -489,10 +489,12 @@ Represents access to a global through runtime reflection, rather than as a manif
489489
perform such accesses.
490490
"""
491491
struct GlobalAccessInfo <: CallInfo
492+
b::Core.Binding
492493
bpart::Core.BindingPartition
493494
end
494-
GlobalAccessInfo(::Nothing) = NoCallInfo()
495-
add_edges_impl(edges::Vector{Any}, info::GlobalAccessInfo) =
496-
push!(edges, info.bpart)
495+
GlobalAccessInfo(::Core.Binding, ::Nothing) = NoCallInfo()
496+
function add_edges_impl(edges::Vector{Any}, info::GlobalAccessInfo)
497+
push!(edges, info.b)
498+
end
497499

498500
@specialize

src/typeinfer.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,8 +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)
547+
elseif isa(item, Core.Binding)
548548
i += 1
549+
maybe_add_binding_backedge!(item, caller)
549550
continue
550551
end
551552
if isa(item, CodeInstance)

test/ssair.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ let code = Any[
134134
Expr(:boundscheck),
135135
Compiler.GotoIfNot(SSAValue(1), 6),
136136
# block 2
137-
Expr(:call, GlobalRef(Base, :size), Compiler.Argument(3)),
137+
Expr(:call, size, Compiler.Argument(3)),
138138
Compiler.ReturnNode(),
139139
# block 3
140140
Core.PhiNode(),

0 commit comments

Comments
 (0)