@@ -18,16 +18,17 @@ import ._TOP_MOD: ==, getindex, setindex!
1818using Core: MethodMatch, SimpleVector, ifelse, sizeof
1919using Core. IR
2020using . _TOP_MOD: # Base definitions
21- @__MODULE__ , @assert , @eval , @goto , @inbounds , @inline , @label , @noinline ,
21+ @__MODULE__ , @assert , @eval , @goto , @inbounds , @inline , @label , @noinline , @show ,
2222 @nospecialize , @specialize , BitSet, Callable, Csize_t, IdDict, IdSet, UnitRange, Vector,
2323 copy, delete!, empty!, enumerate, error, first, get, get!, haskey, in, isassigned,
2424 isempty, ismutabletype, keys, last, length, max, min, missing , pop!, push!, pushfirst!,
2525 unwrap_unionall, ! , != , != = , & , * , + , - , :, < , << , => , > , | , ∈ , ∉ , ∩ , ∪ , ≠ , ≤ , ≥ , ⊆
2626using Core. Compiler: # Core.Compiler specific definitions
27- Bottom, IRCode, IR_FLAG_NOTHROW, InferenceResult, SimpleInferenceLattice,
27+ AbstractLattice, Bottom, IRCode, IR_FLAG_NOTHROW, InferenceResult, SimpleInferenceLattice,
2828 argextype, fieldcount_noerror, hasintersect, has_flag, intrinsic_nothrow,
29- is_meta_expr_head, isbitstype, isexpr, println, setfield!_nothrow, singleton_type,
30- try_compute_field, try_compute_fieldidx, widenconst, ⊑ , AbstractLattice
29+ is_meta_expr_head, is_mutation_free_argtype, isbitstype, isexpr, println,
30+ setfield!_nothrow, singleton_type, try_compute_field, try_compute_fieldidx, widenconst,
31+ ⊑
3132
3233include (x) = _TOP_MOD. include (@__MODULE__ , x)
3334if _TOP_MOD === Core. Compiler
@@ -657,11 +658,13 @@ function analyze_escapes(ir::IRCode, nargs::Int, 𝕃ₒ::AbstractLattice, get_e
657658 # `escape_exception!` conservatively propagates `AllEscape` anyway,
658659 # and so escape information imposed on `:the_exception` isn't computed
659660 continue
661+ elseif head === :gc_preserve_begin
662+ # GC preserve is handled by `escape_gc_preserve!`
663+ elseif head === :gc_preserve_end
664+ escape_gc_preserve! (astate, pc, stmt. args)
660665 elseif head === :static_parameter || # this exists statically, not interested in its escape
661- head === :copyast || # XXX can this account for some escapes?
662- head === :isdefined || # just returns `Bool`, nothing accounts for any escapes
663- head === :gc_preserve_begin || # `GC.@preserve` expressions themselves won't be used anywhere
664- head === :gc_preserve_end # `GC.@preserve` expressions themselves won't be used anywhere
666+ head === :copyast || # XXX escape something?
667+ head === :isdefined # just returns `Bool`, nothing accounts for any escapes
665668 continue
666669 else
667670 add_conservative_changes! (astate, pc, stmt. args)
@@ -1062,17 +1065,27 @@ end
10621065function escape_invoke! (astate:: AnalysisState , pc:: Int , args:: Vector{Any} )
10631066 mi = first (args):: MethodInstance
10641067 first_idx, last_idx = 2 , length (args)
1068+ add_liveness_changes! (astate, pc, args, first_idx, last_idx)
10651069 # TODO inspect `astate.ir.stmts[pc][:info]` and use const-prop'ed `InferenceResult` if available
10661070 cache = astate. get_escape_cache (mi)
1071+ ret = SSAValue (pc)
10671072 if cache isa Bool
10681073 if cache
1069- return nothing # guaranteed to have no escape
1074+ # This method call is very simple and has good effects, so there's no need to
1075+ # escape its arguments. However, since the arguments might be returned, we need
1076+ # to consider the possibility of aliasing between them and the return value.
1077+ for argidx = first_idx: last_idx
1078+ arg = args[argidx]
1079+ if ! is_mutation_free_argtype (argextype (arg, astate. ir))
1080+ add_alias_change! (astate, ret, arg)
1081+ end
1082+ end
1083+ return nothing
10701084 else
10711085 return add_conservative_changes! (astate, pc, args, 2 )
10721086 end
10731087 end
10741088 cache = cache:: ArgEscapeCache
1075- ret = SSAValue (pc)
10761089 retinfo = astate. estate[ret] # escape information imposed on the call statement
10771090 method = mi. def:: Method
10781091 nargs = Int (method. nargs)
@@ -1160,6 +1173,17 @@ function escape_foreigncall!(astate::AnalysisState, pc::Int, args::Vector{Any})
11601173 end
11611174end
11621175
1176+ function escape_gc_preserve! (astate:: AnalysisState , pc:: Int , args:: Vector{Any} )
1177+ @assert length (args) == 1 " invalid :gc_preserve_end"
1178+ val = args[1 ]
1179+ @assert val isa SSAValue " invalid :gc_preserve_end"
1180+ beginstmt = astate. ir[val][:stmt ]
1181+ @assert isexpr (beginstmt, :gc_preserve_begin ) " invalid :gc_preserve_end"
1182+ beginargs = beginstmt. args
1183+ # COMBAK we might need to add liveness for all statements from `:gc_preserve_begin` to `:gc_preserve_end`
1184+ add_liveness_changes! (astate, pc, beginargs)
1185+ end
1186+
11631187normalize (@nospecialize x) = isa (x, QuoteNode) ? x. value : x
11641188
11651189function escape_call! (astate:: AnalysisState , pc:: Int , args:: Vector{Any} )
@@ -1185,20 +1209,12 @@ function escape_call!(astate::AnalysisState, pc::Int, args::Vector{Any})
11851209 if result === missing
11861210 # if this call hasn't been handled by any of pre-defined handlers, escape it conservatively
11871211 add_conservative_changes! (astate, pc, args)
1188- return
11891212 elseif result === true
11901213 add_liveness_changes! (astate, pc, args, 2 )
1191- return # ThrownEscape is already checked
1214+ elseif is_nothrow (astate. ir, pc)
1215+ add_liveness_changes! (astate, pc, args, 2 )
11921216 else
1193- # we escape statements with the `ThrownEscape` property using the effect-freeness
1194- # computed by `stmt_effect_flags` invoked within inlining
1195- # TODO throwness ≠ "effect-free-ness"
1196- if is_nothrow (astate. ir, pc)
1197- add_liveness_changes! (astate, pc, args, 2 )
1198- else
1199- add_fallback_changes! (astate, pc, args, 2 )
1200- end
1201- return
1217+ add_fallback_changes! (astate, pc, args, 2 )
12021218 end
12031219end
12041220
@@ -1526,4 +1542,12 @@ function escape_array_copy!(astate::AnalysisState, pc::Int, args::Vector{Any})
15261542 add_liveness_changes! (astate, pc, args, 6 )
15271543end
15281544
1545+ function escape_builtin! (:: typeof (Core. finalizer), astate:: AnalysisState , pc:: Int , args:: Vector{Any} )
1546+ if length (args) ≥ 3
1547+ obj = args[3 ]
1548+ add_liveness_change! (astate, obj, pc) # TODO setup a proper FinalizerEscape?
1549+ end
1550+ return false
1551+ end
1552+
15291553end # baremodule EscapeAnalysis
0 commit comments