From 7ec7d51c5decb9f4bfba9874e5cd5bc2fb6d4cf3 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki Date: Tue, 13 Feb 2024 01:41:58 +0900 Subject: [PATCH 1/2] wip: use `InternalCodeCache` --- src/interpreter.jl | 23 ++++++++++++++++------- test/setup.jl | 13 ++++++++----- test/test_Cthulhu.jl | 12 +++--------- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/interpreter.jl b/src/interpreter.jl index 84e97852..b42f3a72 100644 --- a/src/interpreter.jl +++ b/src/interpreter.jl @@ -24,7 +24,7 @@ end const InferenceKey = Union{MethodInstance,InferenceResult} const InferenceDict{T} = IdDict{InferenceKey, T} -const OptimizationDict = IdDict{MethodInstance, CodeInstance} +const OptimizationDict = @static VERSION ≥ v"1.11.0-DEV.1552" ? Nothing : IdDict{MethodInstance, CodeInstance} const PC2Remarks = Vector{Pair{Int, String}} const PC2Effects = Dict{Int, Effects} const PC2Excts = Dict{Int, Any} @@ -65,26 +65,35 @@ end #=CC.=#get_inference_world(interp::CthulhuInterpreter) = get_inference_world(interp.native) CC.get_inference_cache(interp::CthulhuInterpreter) = get_inference_cache(interp.native) -# No need to do any locking since we're not putting our results into the runtime cache -CC.lock_mi_inference(interp::CthulhuInterpreter, mi::MethodInstance) = nothing -CC.unlock_mi_inference(interp::CthulhuInterpreter, mi::MethodInstance) = nothing CC.method_table(interp::CthulhuInterpreter) = method_table(interp.native) -if isdefined(CC, :cache_owner) +@static if VERSION ≥ v"1.11.0-DEV.1552" struct CthulhuCacheToken token end CC.cache_owner(interp::CthulhuInterpreter) = CthulhuCacheToken(CC.cache_owner(interp.native)) +struct CodeCacheView{CodeCache} + code_cache::CodeCache end - +CodeCacheView(interp::CthulhuInterpreter) = CodeCacheView(CC.code_cache(interp)) +function Base.getproperty(interp::CthulhuInterpreter, name::Symbol) + if name === :opt + return CodeCacheView(interp) + end + return getfield(interp, name) +end +Base.get(view::CodeCacheView, mi::MethodInstance, default) = CC.get(view.code_cache, mi, default) +Base.getindex(view::CodeCacheView, mi::MethodInstance) = CC.getindex(view.code_cache, mi) +Base.haskey(view::CodeCacheView, mi::MethodInstance) = CC.haskey(view.code_cache, mi) +else struct CthulhuCache cache::OptimizationDict end - CC.code_cache(interp::CthulhuInterpreter) = WorldView(CthulhuCache(interp.opt), WorldRange(get_inference_world(interp))) CC.get(wvc::WorldView{CthulhuCache}, mi::MethodInstance, default) = get(wvc.cache.cache, mi, default) CC.haskey(wvc::WorldView{CthulhuCache}, mi::MethodInstance) = haskey(wvc.cache.cache, mi) CC.setindex!(wvc::WorldView{CthulhuCache}, ci::CodeInstance, mi::MethodInstance) = setindex!(wvc.cache.cache, ci, mi) +end CC.may_optimize(interp::CthulhuInterpreter) = true CC.may_compress(interp::CthulhuInterpreter) = false diff --git a/test/setup.jl b/test/setup.jl index 8e0dfd87..ec54365b 100644 --- a/test/setup.jl +++ b/test/setup.jl @@ -3,13 +3,16 @@ if isdefined(parentmodule(@__MODULE__), :VSCodeServer) using ..VSCodeServer end -function cthulhu_info(@nospecialize(f), @nospecialize(TT=()); optimize=true) - (interp, mi) = Cthulhu.mkinterp(Core.Compiler.NativeInterpreter(), f, TT) - (; src, rt, exct, infos, slottypes, effects) = Cthulhu.lookup(interp, mi, optimize; allow_no_src=true) +function cthulhu_info(@nospecialize(f), @nospecialize(tt=()); + optimize=true, interp=Core.Compiler.NativeInterpreter()) + (interp, mi) = Cthulhu.mkinterp(f, tt; interp) + (; src, rt, exct, infos, slottypes, effects) = + Cthulhu.lookup(interp, mi, optimize; allow_no_src=true) if src !== nothing - src = Cthulhu.preprocess_ci!(src, mi, optimize, Cthulhu.CthulhuConfig(dead_code_elimination=true)) + config = Cthulhu.CthulhuConfig(; dead_code_elimination=true) + src = Cthulhu.preprocess_ci!(src, mi, optimize, config) end - (; interp, src, infos, mi, rt, exct, slottypes, effects) + return (; interp, src, infos, mi, rt, exct, slottypes, effects) end function find_callsites_by_ftt(@nospecialize(f), @nospecialize(TT=Tuple{}); optimize=true) diff --git a/test/test_Cthulhu.jl b/test/test_Cthulhu.jl index 2f902252..95d484ec 100644 --- a/test/test_Cthulhu.jl +++ b/test/test_Cthulhu.jl @@ -268,12 +268,12 @@ end end t[1] end - @test length(callsites) == 1 # getindex(::Union{Vector{Any}, Const(tuple(1,nothing))}, ::Const(1)) + @test length(callsites) == 1 # getindex(::Union{Vector{Any}, Const(tuple(1,nothing))}, ::Const(1)) callinfo = callsites[1].info @test isa(callinfo, Cthulhu.MultiCallInfo) callinfos = callinfo.callinfos @test length(callinfos) == 2 - @test count(ci->isa(ci, Cthulhu.MICallInfo), callinfos) == 1 # getindex(::Vector{Any}, ::Const(1)) + @test count(ci->isa(ci, Cthulhu.MICallInfo), callinfos) == 1 # getindex(::Vector{Any}, ::Const(1)) @test count(ci->isa(ci, Cthulhu.ConstPropCallInfo) || isa(ci, Cthulhu.SemiConcreteCallInfo), callinfos) == 1 # getindex(::Const(tuple(1,nothing)), ::Const(1)) end @@ -1015,13 +1015,7 @@ end let (interp, mi) = Cthulhu.mkinterp((Int,)) do var::Int countvars50037(1, var) end - key = nothing - for (mi, codeinst) in interp.opt - if mi.def.name === :countvars50037 - key = mi - break - end - end + key = only(Base.specializations(only(methods(countvars50037)))) codeinst = interp.opt[key] inferred = @atomic :monotonic codeinst.inferred @test length(inferred.ir.cfg.blocks) == 1 From d4fb5030dad43c1d847735e8a3d0914b53788b4e Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki Date: Tue, 13 Feb 2024 15:43:58 +0900 Subject: [PATCH 2/2] keep the external code cache design --- src/interpreter.jl | 31 +++++++++++-------------------- test/test_AbstractInterpreter.jl | 4 ++-- test/test_Cthulhu.jl | 4 ++++ 3 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/interpreter.jl b/src/interpreter.jl index b42f3a72..335b462b 100644 --- a/src/interpreter.jl +++ b/src/interpreter.jl @@ -24,7 +24,7 @@ end const InferenceKey = Union{MethodInstance,InferenceResult} const InferenceDict{T} = IdDict{InferenceKey, T} -const OptimizationDict = @static VERSION ≥ v"1.11.0-DEV.1552" ? Nothing : IdDict{MethodInstance, CodeInstance} +const OptimizationDict = IdDict{MethodInstance, CodeInstance} const PC2Remarks = Vector{Pair{Int, String}} const PC2Effects = Dict{Int, Effects} const PC2Excts = Dict{Int, Any} @@ -65,27 +65,24 @@ end #=CC.=#get_inference_world(interp::CthulhuInterpreter) = get_inference_world(interp.native) CC.get_inference_cache(interp::CthulhuInterpreter) = get_inference_cache(interp.native) +CC.may_optimize(interp::CthulhuInterpreter) = true +CC.may_compress(interp::CthulhuInterpreter) = false +CC.may_discard_trees(interp::CthulhuInterpreter) = false +CC.verbose_stmt_info(interp::CthulhuInterpreter) = true + CC.method_table(interp::CthulhuInterpreter) = method_table(interp.native) @static if VERSION ≥ v"1.11.0-DEV.1552" +# Since the cache for `CthulhuInterpreter` is volatile and does not involve with the +# internal code cache, technically, there's no requirement to supply `cache_owner` as an +# identifier for the internal code cache. However, the definition of `cache_owner` is +# necessary for utilizing the default `CodeInstance` constructor, define the overload here. struct CthulhuCacheToken token end CC.cache_owner(interp::CthulhuInterpreter) = CthulhuCacheToken(CC.cache_owner(interp.native)) -struct CodeCacheView{CodeCache} - code_cache::CodeCache -end -CodeCacheView(interp::CthulhuInterpreter) = CodeCacheView(CC.code_cache(interp)) -function Base.getproperty(interp::CthulhuInterpreter, name::Symbol) - if name === :opt - return CodeCacheView(interp) - end - return getfield(interp, name) end -Base.get(view::CodeCacheView, mi::MethodInstance, default) = CC.get(view.code_cache, mi, default) -Base.getindex(view::CodeCacheView, mi::MethodInstance) = CC.getindex(view.code_cache, mi) -Base.haskey(view::CodeCacheView, mi::MethodInstance) = CC.haskey(view.code_cache, mi) -else + struct CthulhuCache cache::OptimizationDict end @@ -93,12 +90,6 @@ CC.code_cache(interp::CthulhuInterpreter) = WorldView(CthulhuCache(interp.opt), CC.get(wvc::WorldView{CthulhuCache}, mi::MethodInstance, default) = get(wvc.cache.cache, mi, default) CC.haskey(wvc::WorldView{CthulhuCache}, mi::MethodInstance) = haskey(wvc.cache.cache, mi) CC.setindex!(wvc::WorldView{CthulhuCache}, ci::CodeInstance, mi::MethodInstance) = setindex!(wvc.cache.cache, ci, mi) -end - -CC.may_optimize(interp::CthulhuInterpreter) = true -CC.may_compress(interp::CthulhuInterpreter) = false -CC.may_discard_trees(interp::CthulhuInterpreter) = false -CC.verbose_stmt_info(interp::CthulhuInterpreter) = true function CC.add_remark!(interp::CthulhuInterpreter, sv::InferenceState, msg) key = CC.any(sv.result.overridden_by_const) ? sv.result : sv.linfo diff --git a/test/test_AbstractInterpreter.jl b/test/test_AbstractInterpreter.jl index aa62c7f4..ece9669c 100644 --- a/test/test_AbstractInterpreter.jl +++ b/test/test_AbstractInterpreter.jl @@ -7,7 +7,7 @@ end const CC = Core.Compiler -if isdefined(CC, :cache_owner) +@static if VERSION ≥ v"1.11.0-DEV.1552" macro newinterp(InterpName) InterpCacheName = QuoteNode(Symbol(string(InterpName, "Cache"))) InterpName = esc(InterpName) @@ -77,7 +77,7 @@ macro newinterp(InterpName) $CC.setindex!(wvc::$CC.WorldView{$InterpCacheName}, ci::$C.CodeInstance, mi::$C.MethodInstance) = setindex!(wvc.cache.dict, ci, mi) end end -end # isdefined(CC, :cache_owner) +end # if VERSION ≥ v"1.11.0-DEV.1552" @doc """ @newinterp NewInterpreter diff --git a/test/test_Cthulhu.jl b/test/test_Cthulhu.jl index 95d484ec..8d6b4fcd 100644 --- a/test/test_Cthulhu.jl +++ b/test/test_Cthulhu.jl @@ -1015,7 +1015,11 @@ end let (interp, mi) = Cthulhu.mkinterp((Int,)) do var::Int countvars50037(1, var) end + @static if VERSION ≥ v"1.10" key = only(Base.specializations(only(methods(countvars50037)))) + else + key = only(methods(countvars50037)).specializations[1] + end codeinst = interp.opt[key] inferred = @atomic :monotonic codeinst.inferred @test length(inferred.ir.cfg.blocks) == 1