Skip to content

Commit 5fe93ee

Browse files
authored
AbstractInterpreter: allow overloading merge_effects! (#46559)
This allows external `AbstractInterpreter`s to observe effects computed for each statement (as like `add_remark!`) and show more fine-grained effects information, e.g. in Cthulhu's code view.
1 parent dc27852 commit 5fe93ee

File tree

3 files changed

+28
-28
lines changed

3 files changed

+28
-28
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1914,7 +1914,7 @@ function abstract_eval_value_expr(interp::AbstractInterpreter, e::Expr, vtypes::
19141914
elseif head === :boundscheck
19151915
return Bool
19161916
elseif head === :the_exception
1917-
merge_effects!(sv, Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE))
1917+
merge_effects!(interp, sv, Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE))
19181918
return Any
19191919
end
19201920
return Any
@@ -1928,7 +1928,7 @@ function abstract_eval_special_value(interp::AbstractInterpreter, @nospecialize(
19281928
elseif isa(e, SlotNumber) || isa(e, Argument)
19291929
return vtypes[slot_id(e)].typ
19301930
elseif isa(e, GlobalRef)
1931-
return abstract_eval_global(e.mod, e.name, sv)
1931+
return abstract_eval_global(interp, e.mod, e.name, sv)
19321932
end
19331933

19341934
return Const(e)
@@ -1976,7 +1976,7 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
19761976
t = Bottom
19771977
else
19781978
callinfo = abstract_call(interp, ArgInfo(ea, argtypes), sv)
1979-
merge_effects!(sv, callinfo.effects)
1979+
merge_effects!(interp, sv, callinfo.effects)
19801980
sv.stmt_info[sv.currpc] = callinfo.info
19811981
t = callinfo.rt
19821982
end
@@ -2037,7 +2037,7 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
20372037
consistent = ALWAYS_FALSE
20382038
nothrow = false
20392039
end
2040-
merge_effects!(sv, Effects(EFFECTS_TOTAL; consistent, nothrow))
2040+
merge_effects!(interp, sv, Effects(EFFECTS_TOTAL; consistent, nothrow))
20412041
elseif ehead === :splatnew
20422042
t, isexact = instanceof_tfunc(abstract_eval_value(interp, e.args[1], vtypes, sv))
20432043
nothrow = false # TODO: More precision
@@ -2055,9 +2055,9 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
20552055
end
20562056
end
20572057
consistent = !ismutabletype(t) ? ALWAYS_TRUE : CONSISTENT_IF_NOTRETURNED
2058-
merge_effects!(sv, Effects(EFFECTS_TOTAL; consistent, nothrow))
2058+
merge_effects!(interp, sv, Effects(EFFECTS_TOTAL; consistent, nothrow))
20592059
elseif ehead === :new_opaque_closure
2060-
merge_effects!(sv, Effects()) # TODO
2060+
merge_effects!(interp, sv, Effects()) # TODO
20612061
t = Union{}
20622062
if length(e.args) >= 4
20632063
ea = e.args
@@ -2101,17 +2101,17 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
21012101
override.inaccessiblememonly ? ALWAYS_TRUE : effects.inaccessiblememonly,
21022102
effects.nonoverlayed)
21032103
end
2104-
merge_effects!(sv, effects)
2104+
merge_effects!(interp, sv, effects)
21052105
elseif ehead === :cfunction
2106-
merge_effects!(sv, EFFECTS_UNKNOWN)
2106+
merge_effects!(interp, sv, EFFECTS_UNKNOWN)
21072107
t = e.args[1]
21082108
isa(t, Type) || (t = Any)
21092109
abstract_eval_cfunction(interp, e, vtypes, sv)
21102110
elseif ehead === :method
2111-
merge_effects!(sv, EFFECTS_UNKNOWN)
2111+
merge_effects!(interp, sv, EFFECTS_UNKNOWN)
21122112
t = (length(e.args) == 1) ? Any : Nothing
21132113
elseif ehead === :copyast
2114-
merge_effects!(sv, EFFECTS_UNKNOWN)
2114+
merge_effects!(interp, sv, EFFECTS_UNKNOWN)
21152115
t = abstract_eval_value(interp, e.args[1], vtypes, sv)
21162116
if t isa Const && t.val isa Expr
21172117
# `copyast` makes copies of Exprs
@@ -2149,7 +2149,7 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
21492149
elseif false
21502150
@label always_throw
21512151
t = Bottom
2152-
merge_effects!(sv, EFFECTS_THROWS)
2152+
merge_effects!(interp, sv, EFFECTS_THROWS)
21532153
else
21542154
t = abstract_eval_value_expr(interp, e, vtypes, sv)
21552155
end
@@ -2178,7 +2178,7 @@ function abstract_eval_global(M::Module, s::Symbol)
21782178
return ty
21792179
end
21802180

2181-
function abstract_eval_global(M::Module, s::Symbol, frame::InferenceState)
2181+
function abstract_eval_global(interp::AbstractInterpreter, M::Module, s::Symbol, frame::InferenceState)
21822182
rt = abstract_eval_global(M, s)
21832183
consistent = inaccessiblememonly = ALWAYS_FALSE
21842184
nothrow = false
@@ -2193,15 +2193,15 @@ function abstract_eval_global(M::Module, s::Symbol, frame::InferenceState)
21932193
elseif isdefined(M,s)
21942194
nothrow = true
21952195
end
2196-
merge_effects!(frame, Effects(EFFECTS_TOTAL; consistent, nothrow, inaccessiblememonly))
2196+
merge_effects!(interp, frame, Effects(EFFECTS_TOTAL; consistent, nothrow, inaccessiblememonly))
21972197
return rt
21982198
end
21992199

22002200
function handle_global_assignment!(interp::AbstractInterpreter, frame::InferenceState, lhs::GlobalRef, @nospecialize(newty))
22012201
effect_free = ALWAYS_FALSE
22022202
nothrow = global_assignment_nothrow(lhs.mod, lhs.name, newty)
22032203
inaccessiblememonly = ALWAYS_FALSE
2204-
merge_effects!(frame, Effects(EFFECTS_TOTAL; effect_free, nothrow, inaccessiblememonly))
2204+
merge_effects!(interp, frame, Effects(EFFECTS_TOTAL; effect_free, nothrow, inaccessiblememonly))
22052205
return nothing
22062206
end
22072207

@@ -2290,12 +2290,12 @@ function widenreturn_noconditional(@nospecialize(rt))
22902290
return widenconst(rt)
22912291
end
22922292

2293-
function handle_control_backedge!(frame::InferenceState, from::Int, to::Int)
2293+
function handle_control_backedge!(interp::AbstractInterpreter, frame::InferenceState, from::Int, to::Int)
22942294
if from > to
22952295
if is_effect_overridden(frame, :terminates_locally)
22962296
# this backedge is known to terminate
22972297
else
2298-
merge_effects!(frame, Effects(EFFECTS_TOTAL; terminates=false))
2298+
merge_effects!(interp, frame, Effects(EFFECTS_TOTAL; terminates=false))
22992299
end
23002300
end
23012301
return nothing
@@ -2331,7 +2331,7 @@ end
23312331
elseif isa(lhs, GlobalRef)
23322332
handle_global_assignment!(interp, frame, lhs, t)
23332333
elseif !isa(lhs, SSAValue)
2334-
merge_effects!(frame, EFFECTS_UNKNOWN)
2334+
merge_effects!(interp, frame, EFFECTS_UNKNOWN)
23352335
end
23362336
return BasicStmtChange(changes, t)
23372337
elseif hd === :method
@@ -2405,7 +2405,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
24052405
@assert length(succs) == 1
24062406
nextbb = succs[1]
24072407
ssavaluetypes[currpc] = Any
2408-
handle_control_backedge!(frame, currpc, stmt.label)
2408+
handle_control_backedge!(interp, frame, currpc, stmt.label)
24092409
@goto branch
24102410
elseif isa(stmt, GotoIfNot)
24112411
condx = stmt.cond
@@ -2443,7 +2443,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
24432443
falsebb = succs[1] == truebb ? succs[2] : succs[1]
24442444
if condval === false
24452445
nextbb = falsebb
2446-
handle_control_backedge!(frame, currpc, stmt.dest)
2446+
handle_control_backedge!(interp, frame, currpc, stmt.dest)
24472447
@goto branch
24482448
else
24492449
# We continue with the true branch, but process the false
@@ -2464,7 +2464,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
24642464
changed = update_bbstate!(frame, falsebb, currstate)
24652465
end
24662466
if changed
2467-
handle_control_backedge!(frame, currpc, stmt.dest)
2467+
handle_control_backedge!(interp, frame, currpc, stmt.dest)
24682468
push!(W, falsebb)
24692469
end
24702470
@goto fallthrough

base/compiler/inferencestate.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,11 +206,11 @@ end
206206

207207
Effects(state::InferenceState) = state.ipo_effects
208208

209-
function merge_effects!(caller::InferenceState, effects::Effects)
209+
function merge_effects!(::AbstractInterpreter, caller::InferenceState, effects::Effects)
210210
caller.ipo_effects = merge_effects(caller.ipo_effects, effects)
211211
end
212-
merge_effects!(caller::InferenceState, callee::InferenceState) =
213-
merge_effects!(caller, Effects(callee))
212+
merge_effects!(interp::AbstractInterpreter, caller::InferenceState, callee::InferenceState) =
213+
merge_effects!(interp, caller, Effects(callee))
214214

215215
is_effect_overridden(sv::InferenceState, effect::Symbol) = is_effect_overridden(sv.linfo, effect)
216216
function is_effect_overridden(linfo::MethodInstance, effect::Symbol)

base/compiler/typeinfer.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -793,18 +793,18 @@ function union_caller_cycle!(a::InferenceState, b::InferenceState)
793793
return
794794
end
795795

796-
function merge_call_chain!(parent::InferenceState, ancestor::InferenceState, child::InferenceState)
796+
function merge_call_chain!(interp::AbstractInterpreter, parent::InferenceState, ancestor::InferenceState, child::InferenceState)
797797
# add backedge of parent <- child
798798
# then add all backedges of parent <- parent.parent
799799
# and merge all of the callers into ancestor.callers_in_cycle
800800
# and ensure that walking the parent list will get the same result (DAG) from everywhere
801801
# Also taint the termination effect, because we can no longer guarantee the absence
802802
# of recursion.
803-
merge_effects!(parent, Effects(EFFECTS_TOTAL; terminates=false))
803+
merge_effects!(interp, parent, Effects(EFFECTS_TOTAL; terminates=false))
804804
while true
805805
add_cycle_backedge!(child, parent, parent.currpc)
806806
union_caller_cycle!(ancestor, child)
807-
merge_effects!(child, Effects(EFFECTS_TOTAL; terminates=false))
807+
merge_effects!(interp, child, Effects(EFFECTS_TOTAL; terminates=false))
808808
child = parent
809809
child === ancestor && break
810810
parent = child.parent::InferenceState
@@ -840,7 +840,7 @@ function resolve_call_cycle!(interp::AbstractInterpreter, linfo::MethodInstance,
840840
poison_callstack(parent, frame)
841841
return true
842842
end
843-
merge_call_chain!(parent, frame, frame)
843+
merge_call_chain!(interp, parent, frame, frame)
844844
return frame
845845
end
846846
for caller in frame.callers_in_cycle
@@ -849,7 +849,7 @@ function resolve_call_cycle!(interp::AbstractInterpreter, linfo::MethodInstance,
849849
poison_callstack(parent, frame)
850850
return true
851851
end
852-
merge_call_chain!(parent, frame, caller)
852+
merge_call_chain!(interp, parent, frame, caller)
853853
return caller
854854
end
855855
end

0 commit comments

Comments
 (0)