@@ -18,7 +18,7 @@ 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!,
@@ -657,11 +657,13 @@ function analyze_escapes(ir::IRCode, nargs::Int, 𝕃ₒ::AbstractLattice, get_e
657657 # `escape_exception!` conservatively propagates `AllEscape` anyway,
658658 # and so escape information imposed on `:the_exception` isn't computed
659659 continue
660+ elseif head === :gc_preserve_begin
661+ # GC preserve is handled by `escape_gc_preserve!`
662+ elseif head === :gc_preserve_end
663+ escape_gc_preserve! (astate, pc, stmt. args)
660664 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
665+ head === :copyast || # XXX escape something?
666+ head === :isdefined # just returns `Bool`, nothing accounts for any escapes
665667 continue
666668 else
667669 add_conservative_changes! (astate, pc, stmt. args)
@@ -1062,17 +1064,21 @@ end
10621064function escape_invoke! (astate:: AnalysisState , pc:: Int , args:: Vector{Any} )
10631065 mi = first (args):: MethodInstance
10641066 first_idx, last_idx = 2 , length (args)
1067+ add_liveness_changes! (astate, pc, args, first_idx, last_idx)
10651068 # TODO inspect `astate.ir.stmts[pc][:info]` and use const-prop'ed `InferenceResult` if available
10661069 cache = astate. get_escape_cache (mi)
1070+ ret = SSAValue (pc)
10671071 if cache isa Bool
10681072 if cache
1073+ for (i, argidx) in enumerate (first_idx: last_idx)
1074+ add_alias_change! (astate, ret, args[argidx])
1075+ end
10691076 return nothing # guaranteed to have no escape
10701077 else
10711078 return add_conservative_changes! (astate, pc, args, 2 )
10721079 end
10731080 end
10741081 cache = cache:: ArgEscapeCache
1075- ret = SSAValue (pc)
10761082 retinfo = astate. estate[ret] # escape information imposed on the call statement
10771083 method = mi. def:: Method
10781084 nargs = Int (method. nargs)
@@ -1160,6 +1166,17 @@ function escape_foreigncall!(astate::AnalysisState, pc::Int, args::Vector{Any})
11601166 end
11611167end
11621168
1169+ function escape_gc_preserve! (astate:: AnalysisState , pc:: Int , args:: Vector{Any} )
1170+ @assert length (args) == 1 " invalid :gc_preserve_end"
1171+ val = args[1 ]
1172+ @assert val isa SSAValue " invalid :gc_preserve_end"
1173+ beginstmt = astate. ir[val][:stmt ]
1174+ @assert isexpr (beginstmt, :gc_preserve_begin ) " invalid :gc_preserve_end"
1175+ beginargs = beginstmt. args
1176+ # COMBAK we might need to add liveness for all statements from `:gc_preserve_begin` to `:gc_preserve_end`
1177+ add_liveness_changes! (astate, pc, beginargs)
1178+ end
1179+
11631180normalize (@nospecialize x) = isa (x, QuoteNode) ? x. value : x
11641181
11651182function escape_call! (astate:: AnalysisState , pc:: Int , args:: Vector{Any} )
@@ -1185,20 +1202,12 @@ function escape_call!(astate::AnalysisState, pc::Int, args::Vector{Any})
11851202 if result === missing
11861203 # if this call hasn't been handled by any of pre-defined handlers, escape it conservatively
11871204 add_conservative_changes! (astate, pc, args)
1188- return
11891205 elseif result === true
11901206 add_liveness_changes! (astate, pc, args, 2 )
1191- return # ThrownEscape is already checked
1207+ elseif is_nothrow (astate. ir, pc)
1208+ add_liveness_changes! (astate, pc, args, 2 )
11921209 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
1210+ add_fallback_changes! (astate, pc, args, 2 )
12021211 end
12031212end
12041213
@@ -1526,4 +1535,12 @@ function escape_array_copy!(astate::AnalysisState, pc::Int, args::Vector{Any})
15261535 add_liveness_changes! (astate, pc, args, 6 )
15271536end
15281537
1538+ function escape_builtin! (:: typeof (Core. finalizer), astate:: AnalysisState , pc:: Int , args:: Vector{Any} )
1539+ if length (args) ≥ 3
1540+ obj = args[3 ]
1541+ add_liveness_change! (astate, obj, pc) # TODO setup a proper FinalizerEscape?
1542+ end
1543+ return false
1544+ end
1545+
15291546end # baremodule EscapeAnalysis
0 commit comments