Skip to content

Commit

Permalink
Implement FinalizerEscape
Browse files Browse the repository at this point in the history
  • Loading branch information
jpsamaroo committed Feb 1, 2022
1 parent 2f4c945 commit 4b8b6bf
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 12 deletions.
3 changes: 3 additions & 0 deletions src/EAUtils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,9 @@ function get_name_color(x::EscapeInfo, symbol::Bool = false)
elseif EA.has_return_escape(x)
name = (getname(EA.ReturnEscape), "")
color = EA.has_thrown_escape(x) ? :yellow : :blue
elseif EA.has_finalizer_escape(x)
name = (getname(EA.FinalizerEscape), "&")
color = EA.has_thrown_escape(x) ? :yellow : :blue
else
name = (nothing, "*")
color = EA.has_thrown_escape(x) ? :yellow : :bold
Expand Down
53 changes: 41 additions & 12 deletions src/EscapeAnalysis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export
has_arg_escape,
has_return_escape,
has_thrown_escape,
has_finalizer_escape,
has_all_escape

const _TOP_MOD = ccall(:jl_base_relative_to, Any, (Any,), EscapeAnalysis)::Module
Expand Down Expand Up @@ -122,6 +123,7 @@ struct EscapeInfo
Analyzed::Bool
ReturnEscape::Bool
ThrownEscape::LivenessSet
FinalizerEscape::Bool
AliasInfo #::Union{IndexableFields,IndexableElements,Unindexable,Bool}
Liveness::LivenessSet
# TODO: ArgEscape::Int
Expand All @@ -130,6 +132,7 @@ struct EscapeInfo
Analyzed::Bool,
ReturnEscape::Bool,
ThrownEscape::LivenessSet,
FinalizerEscape::Bool,
AliasInfo#=::Union{IndexableFields,IndexableElements,Unindexable,Bool}=#,
Liveness::LivenessSet,
)
Expand All @@ -138,6 +141,7 @@ struct EscapeInfo
Analyzed,
ReturnEscape,
ThrownEscape,
FinalizerEscape,
AliasInfo,
Liveness,
)
Expand All @@ -150,13 +154,15 @@ struct EscapeInfo
Analyzed::Bool = x.Analyzed,
ReturnEscape::Bool = x.ReturnEscape,
ThrownEscape::LivenessSet = x.ThrownEscape,
FinalizerEscape::Bool = x.FinalizerEscape,
Liveness::LivenessSet = x.Liveness,
)
@nospecialize AliasInfo
return new(
Analyzed,
ReturnEscape,
ThrownEscape,
FinalizerEscape,
AliasInfo,
Liveness,
)
Expand All @@ -177,13 +183,14 @@ const TOP_LIVENESS = LivenessSet(-1:0)
const ARG_LIVENESS = LivenessSet(0)

# the constructors
NotAnalyzed() = EscapeInfo(false, false, BOT_THROWN_ESCAPE, false, BOT_LIVENESS) # not formally part of the lattice
NoEscape() = EscapeInfo(true, false, BOT_THROWN_ESCAPE, false, BOT_LIVENESS)
ArgEscape() = EscapeInfo(true, false, BOT_THROWN_ESCAPE, true, ARG_LIVENESS)
ReturnEscape(pc::Int) = EscapeInfo(true, true, BOT_THROWN_ESCAPE, false, LivenessSet(pc))
AllReturnEscape() = EscapeInfo(true, true, BOT_THROWN_ESCAPE, false, TOP_LIVENESS)
ThrownEscape(pc::Int) = EscapeInfo(true, false, LivenessSet(pc), false, BOT_LIVENESS)
AllEscape() = EscapeInfo(true, true, TOP_THROWN_ESCAPE, true, TOP_LIVENESS)
NotAnalyzed() = EscapeInfo(false, false, BOT_THROWN_ESCAPE, false, false, BOT_LIVENESS) # not formally part of the lattice
NoEscape() = EscapeInfo(true, false, BOT_THROWN_ESCAPE, false, false, BOT_LIVENESS)
ArgEscape() = EscapeInfo(true, false, BOT_THROWN_ESCAPE, false, true, ARG_LIVENESS)
ReturnEscape(pc::Int) = EscapeInfo(true, true, BOT_THROWN_ESCAPE, false, false, LivenessSet(pc))
AllReturnEscape() = EscapeInfo(true, true, BOT_THROWN_ESCAPE, false, false, TOP_LIVENESS)
ThrownEscape(pc::Int) = EscapeInfo(true, false, LivenessSet(pc), false, false, BOT_LIVENESS)
FinalizerEscape(pc::Int) = EscapeInfo(true, false, BOT_THROWN_ESCAPE, true, false, LivenessSet(pc))
AllEscape() = EscapeInfo(true, true, TOP_THROWN_ESCAPE, true, true, TOP_LIVENESS)

const ⊥, ⊤ = NotAnalyzed(), AllEscape()

Expand All @@ -193,7 +200,9 @@ has_arg_escape(x::EscapeInfo) = 0 in x.Liveness
has_return_escape(x::EscapeInfo) = x.ReturnEscape
has_return_escape(x::EscapeInfo, pc::Int) = x.ReturnEscape && (-1 x.Liveness || pc in x.Liveness)
has_thrown_escape(x::EscapeInfo) = !isempty(x.ThrownEscape)
has_thrown_escape(x::EscapeInfo, pc::Int) = -1 x.ThrownEscape || pc in x.ThrownEscape
has_thrown_escape(x::EscapeInfo, pc::Int) = -1 x.ThrownEscape || pc in x.ThrownEscape
has_finalizer_escape(x::EscapeInfo) = x.FinalizerEscape
has_finalizer_escape(x::EscapeInfo, pc::Int) = x.FinalizerEscape && (-1 x.Liveness || pc in x.Liveness)
has_all_escape(x::EscapeInfo) =ₑ x

# utility lattice constructors
Expand All @@ -217,6 +226,7 @@ x::EscapeInfo == y::EscapeInfo = begin
else
xt == yt || return false
end
x.FinalizerEscape === y.FinalizerEscape || return false
xa, ya = x.AliasInfo, y.AliasInfo
if isa(xa, Bool)
xa === ya || return false
Expand Down Expand Up @@ -267,6 +277,7 @@ x::EscapeInfo ⊑ₑ y::EscapeInfo = begin
elseif yt !== TOP_THROWN_ESCAPE
xt yt || return false
end
x.FinalizerEscape y.FinalizerEscape || return false
xa, ya = x.AliasInfo, y.AliasInfo
if isa(xa, Bool)
xa && ya !== true && return false
Expand Down Expand Up @@ -442,6 +453,7 @@ x::EscapeInfo ⊔ₑ y::EscapeInfo = begin
x.Analyzed | y.Analyzed,
x.ReturnEscape | y.ReturnEscape,
ThrownEscape,
x.FinalizerEscape | y.FinalizerEscape,
AliasInfo,
Liveness,
)
Expand Down Expand Up @@ -559,13 +571,14 @@ struct ArgEscapeInfo
AllEscape::Bool
ReturnEscape::Bool
ThrownEscape::Bool
FinalizerEscape::Bool
ArgAliasing::Union{Nothing,Vector{Int}}
end

function ArgEscapeInfo(x::EscapeInfo, ArgAliasing::Union{Nothing,Vector{Int}})
x ===&& return ArgEscapeInfo(true, true, true, nothing)
ThrownEscape = isempty(x.ThrownEscape) ? false : true
return ArgEscapeInfo(false, x.ReturnEscape, ThrownEscape, ArgAliasing)
return ArgEscapeInfo(false, x.ReturnEscape, ThrownEscape, x.FinalizerEscape, ArgAliasing)
end

# when working outside of Core.Compiler, cache as much as information for later inspection and debugging
Expand Down Expand Up @@ -1435,10 +1448,10 @@ function escape_foreigncall!(astate::AnalysisState, pc::Int, args::Vector{Any})
elseif is_array_isassigned(nn)
escape_array_isassigned!(astate, pc, args)
return
elseif is_finalizer(nn)
escape_finalizer!(astate, pc, args)
return
end
# if nn === :jl_gc_add_finalizer_th
# # TODO add `FinalizerEscape` ?
# end
end
# NOTE array allocations might have been proven as nothrow (https://github.com/JuliaLang/julia/pull/43565)
nothrow = is_effect_free(astate.ir, pc)
Expand Down Expand Up @@ -1991,6 +2004,22 @@ function array_isassigned_nothrow(args::Vector{Any}, src::IRCode)
return true
end

is_finalizer(name::Symbol) = name === :jl_gc_add_finalizer_th

function escape_finalizer!(astate::AnalysisState, pc::Int, args::Vector{Any})
length(args) 6 || return add_fallback_changes!(astate, pc, args)
println("Finalizer escape!")
println(pc)
for arg in args
println(arg)
end
value = args[8]
func = args[9]
# TODO: We need to analyze func
add_escape_change!(astate, value, FinalizerEscape(pc))
add_liveness_changes!(astate, pc, args, 6)
end

# # COMBAK do we want to enable this (and also backport this to Base for array allocations?)
# import Core.Compiler: Cint, svec
# function validate_foreigncall_args(args::Vector{Any},
Expand Down

0 comments on commit 4b8b6bf

Please sign in to comment.