From b9acd6564612a6b55cbeb77beb42ca6b4855ece4 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Fri, 21 Feb 2025 01:36:04 +0900 Subject: [PATCH] prepare for updating to 1.12, require 1.11 as the minimum compat (#691) * bump to v0.10, compat with Julia 1.11 and higher, remove outdated compat * use `analysis_results` for caching analysis results Which allows us to simplify overloads related to the management of analysis result cache. * fix typo --- .github/workflows/ci.yml | 2 +- Project.toml | 4 +- docs/src/internals.md | 1 - src/JETBase.jl | 62 ++----- src/abstractinterpret/abstractanalyzer.jl | 52 +----- src/abstractinterpret/typeinfer.jl | 200 +++------------------- src/analyzers/jetanalyzer.jl | 57 +----- src/analyzers/optanalyzer.jl | 20 +-- test/analyzers/test_jetanalyzer.jl | 36 ++-- test/self_check.jl | 2 +- test/test_misc.jl | 6 +- test/toplevel/test_virtualprocess.jl | 8 +- 12 files changed, 70 insertions(+), 380 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 06240b617..8ba7b3246 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: - version: '1' # current stable os: ubuntu-latest arch: x64 - - version: '1.10.0' # lowerest version supported + - version: '1.11' # lowest version supported os: ubuntu-latest arch: x64 - version: '1.12-nightly' # next release diff --git a/Project.toml b/Project.toml index af241d81b..9cab933d5 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "JET" uuid = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" authors = ["Shuhei Kadowaki "] -version = "0.9.18" +version = "0.10.0" [deps] CodeTracking = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" @@ -44,7 +44,7 @@ Revise = "3.3" StaticArrays = "1.7.0" TOML = "1.0.3" Test = "1.10" -julia = "1.10" +julia = "1.11" [extras] Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" diff --git a/docs/src/internals.md b/docs/src/internals.md index 56e6a1b3a..0e4ee7771 100644 --- a/docs/src/internals.md +++ b/docs/src/internals.md @@ -22,7 +22,6 @@ passing `AbstractAnalyzer` to the subsequent (maybe overloaded) callees. JET.AnalysisResult JET.CachedAnalysisResult JET.AnalysisCache -Core.Compiler.inlining_policy ``` ## [Top-level Analysis](@id toplevel) diff --git a/src/JETBase.jl b/src/JETBase.jl index 26f10984f..b4610c3e2 100644 --- a/src/JETBase.jl +++ b/src/JETBase.jl @@ -89,23 +89,9 @@ __init__() = foreach(@nospecialize(f)->f(), INIT_HOOKS) # compat # ------ -@static if VERSION ≥ v"1.11.0-DEV.439" - using Base: generating_output -else - function generating_output(incremental::Union{Bool,Nothing}=nothing) - ccall(:jl_generating_output, Cint, ()) == 0 && return false - if incremental !== nothing - Base.JLOptions().incremental == incremental || return false - end - return true - end -end +using Base: generating_output -@static if VERSION ≥ v"1.11.0-DEV.1498" - import .CC: get_inference_world -else - import .CC: get_world_counter as get_inference_world -end +import .CC: get_inference_world # macros # ------ @@ -682,17 +668,10 @@ function analyze_method_instance!(analyzer::AbstractAnalyzer, mi::MethodInstance return analyze_frame!(analyzer, frame) end -@static if VERSION ≥ v"1.11.0-DEV.843" function InferenceState(result::InferenceResult, cache_mode::UInt8, analyzer::AbstractAnalyzer) init_result!(analyzer, result) return @invoke InferenceState(result::InferenceResult, cache_mode::UInt8, analyzer::AbstractInterpreter) end -else -function InferenceState(result::InferenceResult, cache_mode::Symbol, analyzer::AbstractAnalyzer) - init_result!(analyzer, result) - return @invoke InferenceState(result::InferenceResult, cache_mode::Symbol, analyzer::AbstractInterpreter) -end -end function analyze_frame!(analyzer::AbstractAnalyzer, frame::InferenceState) set_entry!(analyzer, frame.linfo) @@ -1201,7 +1180,7 @@ include("analyzers/jetanalyzer.jl") include("analyzers/optanalyzer.jl") using PrecompileTools -@static v"1.11.0-DEV.1552" > VERSION && @setup_workload let +false && @setup_workload let @compile_workload let result = @report_call sum("julia") show(IOContext(devnull, :color=>true), result) @@ -1212,30 +1191,21 @@ using PrecompileTools result = @report_opt rand(String) show(IOContext(devnull, :color=>true), result) end - @static VERSION ≥ v"1.11.0-DEV.1255" && let - # register an initialization callback that fixes up `max_world` which is overridden - # to `one(UInt) == WORLD_AGE_REVALIDATION_SENTINEL` by staticdata.c - # otherwise using cached analysis results would result in world age assertion error - function override_precompiled_cache() - for precache in (JET_ANALYZER_CACHE, OPT_ANALYZER_CACHE), - (_, cache) in precache - for (_, codeinst) in cache.cache - @static if VERSION ≥ v"1.11.0-DEV.1390" - if ((@atomic :monotonic codeinst.min_world) > zero(UInt) && - (@atomic :monotonic codeinst.max_world) == one(UInt)) # == WORLD_AGE_REVALIDATION_SENTINEL - @atomic :monotonic codeinst.max_world = typemax(UInt) - end - else - if (codeinst.min_world > zero(UInt) && - codeinst.max_world == one(UInt)) # == WORLD_AGE_REVALIDATION_SENTINEL - codeinst.max_world = typemax(UInt) - end - end + # register an initialization callback that fixes up `max_world` which is overridden + # to `one(UInt) == WORLD_AGE_REVALIDATION_SENTINEL` by staticdata.c + # otherwise using cached analysis results would result in world age assertion error + function override_precompiled_cache() + for precache in (JET_ANALYZER_CACHE, OPT_ANALYZER_CACHE), + (_, cache) in precache + for (_, codeinst) in cache.cache + if ((@atomic :monotonic codeinst.min_world) > zero(UInt) && + (@atomic :monotonic codeinst.max_world) == one(UInt)) # == WORLD_AGE_REVALIDATION_SENTINEL + @atomic :monotonic codeinst.max_world = typemax(UInt) end - Base.rehash!(cache.cache) # HACK to avoid JuliaLang/julia#52915 end + Base.rehash!(cache.cache) # HACK to avoid JuliaLang/julia#52915 end - override_precompiled_cache() # to precompile this callback itself - push_inithook!(override_precompiled_cache) end + override_precompiled_cache() # to precompile this callback itself + push_inithook!(override_precompiled_cache) end diff --git a/src/abstractinterpret/abstractanalyzer.jl b/src/abstractinterpret/abstractanalyzer.jl index 929aaadf7..c42a74b47 100644 --- a/src/abstractinterpret/abstractanalyzer.jl +++ b/src/abstractinterpret/abstractanalyzer.jl @@ -76,13 +76,9 @@ a global cache maintained by `AbstractAnalyzer`. That means, is expected to have its field `codeinf.inferred::CachedAnalysisResult`. """ struct CachedAnalysisResult - src reports::Vector{InferenceErrorReport} - CachedAnalysisResult(@nospecialize(src), reports::Vector{InferenceErrorReport}) = new(src, reports) end -const AnyAnalysisResult = Union{AnalysisResult,CachedAnalysisResult} - """ mutable struct AnalyzerState ... @@ -119,7 +115,7 @@ mutable struct AnalyzerState ## AbstractAnalyzer ## - results::IdDict{InferenceResult,AnyAnalysisResult} + results::IdDict{InferenceResult,AnalysisResult} # the temporal stash to keep reports that are collected within the currently-analyzed frame: # they will be appended to the caller when returning back to the caller inference/optimization @@ -158,7 +154,7 @@ for fld in fieldnames(AnalyzerState) end function AnalyzerState(world::UInt = get_world_counter(); - results::IdDict{InferenceResult,AnyAnalysisResult} = IdDict{InferenceResult,AnyAnalysisResult}(), + results::IdDict{InferenceResult,AnalysisResult} = IdDict{InferenceResult,AnalysisResult}(), inf_params::Union{Nothing,InferenceParams} = nothing, opt_params::Union{Nothing,OptimizationParams} = nothing, concretized::BitVector = _CONCRETIZED, @@ -174,7 +170,7 @@ function AnalyzerState(world::UInt = get_world_counter(); #=inf_cache::Vector{InferenceResult}=# inf_cache, #=inf_params::InferenceParams=# inf_params, #=opt_params::OptimizationParams=# opt_params, - #=results::IdDict{InferenceResult,AnyAnalysisResult}=# results, + #=results::IdDict{InferenceResult,AnalysisResult}=# results, #=report_stash::Vector{InferenceErrorReport}=# report_stash, #=cache_target::Union{Nothing,Pair{Symbol,InferenceState}}=# nothing, #=concretized::BitVector=# concretized, @@ -504,21 +500,14 @@ end # define how AbstractAnalyzer manages `InferenceResult` Base.getindex(analyzer::AbstractAnalyzer, result::InferenceResult) = get_results(analyzer)[result] -Base.setindex!(analyzer::AbstractAnalyzer, analysis_result::AnyAnalysisResult, result::InferenceResult) = - get_results(analyzer)[result] = analysis_result +Base.setindex!(analyzer::AbstractAnalyzer, analysis_result::AnalysisResult, result::InferenceResult) = get_results(analyzer)[result] = analysis_result function init_result!(analyzer::AbstractAnalyzer, result::InferenceResult) analyzer[result] = AnalysisResult(InferenceErrorReport[]) return nothing end -function set_cached_result!(analyzer::AbstractAnalyzer, result::InferenceResult, cache::Vector{InferenceErrorReport}) - analyzer[result] = CachedAnalysisResult(result.src, cache) - return nothing -end get_reports(analyzer::AbstractAnalyzer, result::InferenceResult) = (analyzer[result]::AnalysisResult).reports -get_cached_reports(analyzer::AbstractAnalyzer, result::InferenceResult) = (analyzer[result]::CachedAnalysisResult).reports -get_any_reports(analyzer::AbstractAnalyzer, result::InferenceResult) = (analyzer[result]::AnyAnalysisResult).reports """ add_new_report!(analyzer::AbstractAnalyzer, result::InferenceResult, report::InferenceErrorReport) @@ -552,36 +541,3 @@ CC.may_compress(::AbstractAnalyzer) = generating_output() # this overload is necessary to avoid caching with the const ABI CC.may_discard_trees(::AbstractAnalyzer) = false - -let # overload `inlining_policy` - @static if VERSION ≥ v"1.11.0-DEV.879" - sigs_ex = :(analyzer::AbstractAnalyzer, @nospecialize(src), @nospecialize(info::CC.CallInfo), stmt_flag::UInt32) - args_ex = :(analyzer::AbstractInterpreter, src::Any, info::CC.CallInfo, stmt_flag::UInt32) - elseif VERSION ≥ v"1.11.0-DEV.377" - sigs_ex = :(analyzer::AbstractAnalyzer, - @nospecialize(src), @nospecialize(info::CC.CallInfo), stmt_flag::UInt32, mi::MethodInstance, argtypes::Argtypes) - args_ex = :(analyzer::AbstractInterpreter, - src::Any, info::CC.CallInfo, stmt_flag::UInt32, mi::MethodInstance, argtypes::Argtypes) - else - sigs_ex = :(analyzer::AbstractAnalyzer, - @nospecialize(src), @nospecialize(info::CC.CallInfo), stmt_flag::UInt8, mi::MethodInstance, argtypes::Argtypes) - args_ex = :(analyzer::AbstractInterpreter, - src::Any, info::CC.CallInfo, stmt_flag::UInt8, mi::MethodInstance, argtypes::Argtypes) - end - @eval begin - @doc """ - inlining_policy(analyzer::AbstractAnalyzer, @nospecialize(src), ...) -> source::Any - - Implements inlining policy for `AbstractAnalyzer`. - Since `AbstractAnalyzer` works on `InferenceResult` whose `src` field keeps - [`AnalysisResult`](@ref) or [`CachedAnalysisResult`](@ref), this implementation needs to forward - their wrapped source to `inlining_policy(::AbstractInterpreter, ::Any, ::UInt8)`. - """ - function CC.inlining_policy($(sigs_ex.args...)) - if isa(src, CachedAnalysisResult) - src = src.src - end - return @invoke CC.inlining_policy($(args_ex.args...)) - end - end -end diff --git a/src/abstractinterpret/typeinfer.jl b/src/abstractinterpret/typeinfer.jl index b9284a8d8..19222f46e 100644 --- a/src/abstractinterpret/typeinfer.jl +++ b/src/abstractinterpret/typeinfer.jl @@ -164,9 +164,7 @@ end # global # ------ -@static if VERSION ≥ v"1.11.0-DEV.1552" CC.cache_owner(analyzer::AbstractAnalyzer) = AnalysisCache(analyzer) -end function CC.code_cache(analyzer::AbstractAnalyzer) view = AbstractAnalyzerView(analyzer) @@ -203,8 +201,11 @@ function CC.get(wvc::WorldView{<:AbstractAnalyzerView}, mi::MethodInstance, defa if context === :typeinf_edge if isa(codeinst, CodeInstance) # cache hit, now we need to append cached reports associated with this `MethodInstance` - inferred = (@atomic :monotonic codeinst.inferred)::CachedAnalysisResult - collect_cached_callee_reports!(analyzer, inferred.reports, caller, mi) + cached_reports = CC.traverse_analysis_results(codeinst) do @nospecialize analysis_result + analysis_result isa CachedAnalysisResult ? analysis_result.reports : nothing + end + cached_reports !== nothing && + collect_cached_callee_reports!(analyzer, cached_reports, caller, mi) end end set_cache_target!(analyzer, nothing) @@ -220,53 +221,7 @@ function CC.getindex(wvc::WorldView{<:AbstractAnalyzerView}, mi::MethodInstance) end function CC.setindex!(wvc::WorldView{<:AbstractAnalyzerView}, codeinst::CodeInstance, mi::MethodInstance) - analysis_cache = AnalysisCache(wvc) - @static if VERSION < v"1.11.0-DEV.1552" - add_jet_callback!(mi, analysis_cache) - end - return analysis_cache[mi] = codeinst -end - -struct JETCallback - analysis_cache::AnalysisCache -end - -@static if VERSION ≥ v"1.11.0-DEV.1552" # nothing to do -elseif VERSION ≥ v"1.11.0-DEV.798" -function add_jet_callback!(mi::MethodInstance, analysis_cache::AnalysisCache) - callback = JETCallback(analysis_cache) - CC.add_invalidation_callback!(callback, mi) -end -function (callback::JETCallback)(replaced::MethodInstance, max_world::UInt32) - delete!(callback.analysis_cache, replaced) -end -else -function add_jet_callback!(mi::MethodInstance, analysis_cache::AnalysisCache) - callback = JETCallback(analysis_cache) - if !isdefined(mi, :callbacks) - mi.callbacks = Any[callback] - else - callbacks = mi.callbacks::Vector{Any} - if !any(@nospecialize(cb)->cb===callback, callbacks) - push!(callbacks, callback) - end - end - return nothing -end -function (callback::JETCallback)(replaced::MethodInstance, max_world::UInt32, - seen::IdSet{MethodInstance} = IdSet{MethodInstance}()) - push!(seen, replaced) - delete!(callback.analysis_cache, replaced) - if isdefined(replaced, :backedges) - for item in replaced.backedges - item isa MethodInstance || continue # might be `Type` object representing an `invoke` signature - mi = item - mi in seen && continue # otherwise fail into an infinite loop - callback(mi, max_world, seen) - end - end - return nothing -end + return AnalysisCache(wvc)[mi] = codeinst end # local @@ -301,7 +256,11 @@ function CC.cache_lookup(𝕃ᵢ::CC.AbstractLattice, mi::MethodInstance, given_ # (see the `CC.typeinf(::AbstractAnalyzer, ::InferenceState)` overload) filter_lineages!(analyzer, caller.result, mi) - collect_cached_callee_reports!(analyzer, get_cached_reports(analyzer, inf_result), caller, mi) + cached_reports = CC.traverse_analysis_results(inf_result) do @nospecialize analysis_result + analysis_result isa CachedAnalysisResult ? analysis_result.reports : nothing + end + cached_reports !== nothing && + collect_cached_callee_reports!(analyzer, cached_reports, caller, mi) end return inf_result end @@ -410,142 +369,37 @@ function finish_frame!(analyzer::AbstractAnalyzer, frame::InferenceState) if frame.parent !== nothing # inter-procedural handling: get back to the caller what we got from these results stash_report!(analyzer, reports) - - # local cache management - # TODO there are duplicated work here and `transform_result_for_cache` - cache_reports_locally!(analyzer, caller, reports) end + + # cache management + cache_reports_locally!(analyzer, caller, reports) end function cache_reports_locally!(analyzer::AbstractAnalyzer, caller::InferenceResult, reports::Vector{InferenceErrorReport}) - cache = InferenceErrorReport[] + cached_reports = InferenceErrorReport[] + mi = caller.linfo for report in reports - cache_report!(cache, report) - end - set_cached_result!(analyzer, caller, cache) -end - -@static if VERSION ≥ v"1.11.0-DEV.737" - -function CC.finish!(analyzer::AbstractAnalyzer, frame::InferenceState) - ret = @invoke CC.finish!(analyzer::AbstractInterpreter, frame::InferenceState) - finish_frame!(analyzer, frame) - return ret -end - -# N.B. this overload essentially reverts JuliaLang/julia#50469 for type stability, -# but this is safe since `AbstractAnalyzer` doesn't currently support any compositions -# with other abstract interpreters -function CC._typeinf(analyzer::AbstractAnalyzer, frame::InferenceState) - CC.typeinf_nocycle(analyzer, frame) || return false # frame is now part of a higher cycle - # with no active ip's, frame is done - frames = frame.callers_in_cycle - isempty(frames) && push!(frames, frame) - valid_worlds = WorldRange() - for caller in frames - @assert !(caller.dont_work_on_me) - caller.dont_work_on_me = true - # might might not fully intersect these earlier, so do that now - valid_worlds = CC.intersect(caller.valid_worlds, valid_worlds) - end - for caller in frames - caller.valid_worlds = valid_worlds - CC.finish(caller, #=CHANGED caller.interp=#analyzer) - end - for caller in frames - opt = caller.result.src - if opt isa OptimizationState{typeof(analyzer)} # CHANGED: added {typeof(analyzer)} - CC.optimize(#=CHANGED caller.interp=#analyzer, opt, caller.result) - end - end - for caller in frames - CC.finish!(#=CHANGED caller.interp=#analyzer, caller) - if CC.is_cached(caller) - CC.cache_result!(#=CHANGED caller.interp=#analyzer, caller.result) - end - end - empty!(frames) - return true -end - -else - -# in this overload we can work on `frame.src::CodeInfo` (and also `frame::InferenceState`) -# where type inference (and also optimization if applied) already ran on -function CC._typeinf(analyzer::AbstractAnalyzer, frame::InferenceState) - CC.typeinf_nocycle(analyzer, frame) || return false # frame is now part of a higher cycle - # with no active ip's, frame is done - frames = frame.callers_in_cycle - isempty(frames) && push!(frames, frame) - valid_worlds = WorldRange() - for caller in frames - @assert !(caller.dont_work_on_me) - caller.dont_work_on_me = true - # might might not fully intersect these earlier, so do that now - valid_worlds = CC.intersect(caller.valid_worlds, valid_worlds) - end - for caller in frames - caller.valid_worlds = valid_worlds - CC.finish(caller, analyzer) - end - for frame in frames - caller = frame.result - opt = caller.src - if opt isa OptimizationState{typeof(analyzer)} - CC.optimize(analyzer, opt, caller) - end - end - for frame in frames - caller = frame.result - edges = frame.stmt_edges[1]::Vector{Any} - valid_worlds = caller.valid_worlds - if CC.last(valid_worlds) >= get_world_counter() - # if we aren't cached, we don't need this edge - # but our caller might, so let's just make it anyways - CC.store_backedges(caller, edges) - end - CC.finish!(analyzer, frame) - # global cache management - if frame.cached && !istoplevel(frame) - CC.cache_result!(analyzer, caller) + @static if JET_DEV_MODE + actual, expected = first(report.vst).linfo, mi + @assert actual === expected "invalid global caching detected, expected $expected but got $actual" end + cache_report!(cached_reports, report) end - empty!(frames) - return true + CC.stack_analysis_result!(caller, CachedAnalysisResult(cached_reports)) end -# by default, this overload just is forwarded to the AbstractInterpreter's implementation -# but the only reason we have this overload is that some analyzers (like `JETAnalyzer`) -# can further overload this to generate `InferenceErrorReport` with an access to `frame` function CC.finish!(analyzer::AbstractAnalyzer, frame::InferenceState) - ret = CC.finish!(analyzer, frame.result) + ret = @invoke CC.finish!(analyzer::AbstractInterpreter, frame::InferenceState) finish_frame!(analyzer, frame) return ret end -end - function CC.cache_result!(analyzer::AbstractAnalyzer, caller::InferenceResult) istoplevel(caller.linfo) && return nothing # don't need to cache toplevel frame @invoke CC.cache_result!(analyzer::AbstractInterpreter, caller::InferenceResult) end -function CC.transform_result_for_cache(analyzer::AbstractAnalyzer, - linfo::MethodInstance, valid_worlds::WorldRange, result::InferenceResult) - cache = InferenceErrorReport[] - for report in get_any_reports(analyzer, result) - @static if JET_DEV_MODE - actual, expected = first(report.vst).linfo, linfo - @assert actual === expected "invalid global caching detected, expected $expected but got $actual" - end - cache_report!(cache, report) - end - inferred_result = @invoke CC.transform_result_for_cache(analyzer::AbstractInterpreter, - linfo::MethodInstance, valid_worlds::WorldRange, result::InferenceResult) - return CachedAnalysisResult(inferred_result, cache) -end - # top-level bridge # ================ @@ -605,13 +459,7 @@ function CC.abstract_eval_special_value(analyzer::AbstractAnalyzer, @nospecializ # in this call graph, but it's highly possible this is a toplevel callsite # and we take a risk here since we can't enter the analysis otherwise val = getglobal(mod, name) - @static if VERSION ≥ v"1.11.0-DEV.945" ret = CC.RTEffects(isa(val, AbstractGlobal) ? val.t : Const(val), ret.exct, ret.effects) - elseif VERSION ≥ v"1.11.0-DEV.797" - ret = CC.RTEffects(isa(val, AbstractGlobal) ? val.t : Const(val), ret.effects) - else - ret = isa(val, AbstractGlobal) ? val.t : Const(val) - end end end end @@ -641,11 +489,7 @@ is_inactive_exception(@nospecialize rt) = isa(rt, Const) && rt.val === _INACTIVE function CC.abstract_eval_statement(analyzer::AbstractAnalyzer, @nospecialize(e), vtypes::VarTable, sv::InferenceState) if istoplevel(sv) if get_concretized(analyzer)[get_currpc(sv)] - @static if VERSION ≥ v"1.11.0-DEV.945" return CC.RTEffects(Any, Any, CC.Effects()) # bail out if it has been interpreted by `ConcreteInterpreter` - else - return Any # bail out if it has been interpreted by `ConcreteInterpreter` - end end end diff --git a/src/analyzers/jetanalyzer.jl b/src/analyzers/jetanalyzer.jl index ae0d3bb07..def0d853d 100644 --- a/src/analyzers/jetanalyzer.jl +++ b/src/analyzers/jetanalyzer.jl @@ -64,18 +64,8 @@ struct JETAnalyzer{RP<:ReportPass} <: AbstractAnalyzer end function JETAnalyzer(state::AnalyzerState, report_pass::ReportPass, config::JETAnalyzerConfig) - if ((@static VERSION < v"1.11.0-DEV.1255" && true) && generating_output()) - # XXX Avoid storing analysis results into a cache that persists across the - # precompilation, as pkgimage currently doesn't support serializing - # externally created `CodeInstance`. Otherwise, `CodeInstance`s created by - # JET, containing JET-specific data structures, will leak into the native - # code cache, likely causing segfaults or undefined behavior. - # (see https://github.com/JuliaLang/julia/issues/48453). - analysis_cache = AnalysisCache() - else - cache_key = compute_hash(state.inf_params, report_pass, config) - analysis_cache = get!(AnalysisCache, JET_ANALYZER_CACHE, cache_key) - end + cache_key = compute_hash(state.inf_params, report_pass, config) + analysis_cache = get!(AnalysisCache, JET_ANALYZER_CACHE, cache_key) return JETAnalyzer(state, analysis_cache, report_pass, config) end end @@ -179,7 +169,6 @@ a package, or improve the accuracy of base abstract interpretation analysis. # overloads # ========= -@static if VERSION ≥ v"1.11.0-DEV.843" function CC.InferenceState(result::InferenceResult, cache_mode::UInt8, analyzer::JETAnalyzer) frame = @invoke CC.InferenceState(result::InferenceResult, cache_mode::UInt8, analyzer::AbstractAnalyzer) if isnothing(frame) # indicates something bad happened within `retrieve_code_info` @@ -187,15 +176,6 @@ function CC.InferenceState(result::InferenceResult, cache_mode::UInt8, analyzer: end return frame end -else -function CC.InferenceState(result::InferenceResult, cache_mode::Symbol, analyzer::JETAnalyzer) - frame = @invoke CC.InferenceState(result::InferenceResult, cache_mode::Symbol, analyzer::AbstractAnalyzer) - if isnothing(frame) # indicates something bad happened within `retrieve_code_info` - ReportPass(analyzer)(GeneratorErrorReport, analyzer, result) - end - return frame -end -end function CC.finish!(analyzer::JETAnalyzer, caller::InferenceState) src = caller.result.src @@ -277,15 +257,9 @@ end function CC.concrete_eval_eligible(analyzer::JETAnalyzer, @nospecialize(f), result::MethodCallResult, arginfo::ArgInfo, sv::InferenceState) if CC.is_nothrow(result.effects) - neweffects = CC.Effects(result.effects; - nonoverlayed=@static VERSION ≥ v"1.11.0-beta2.49" ? CC.ALWAYS_TRUE : true) - @static if VERSION ≥ v"1.11.0-DEV.945" + neweffects = CC.Effects(result.effects; nonoverlayed=CC.ALWAYS_TRUE) newresult = MethodCallResult(result.rt, result.exct, result.edgecycle, result.edgelimited, result.edge, neweffects) - else - newresult = MethodCallResult(result.rt, result.edgecycle, result.edgelimited, - result.edge, neweffects) - end res = @invoke CC.concrete_eval_eligible(analyzer::AbstractAnalyzer, f::Any, newresult::MethodCallResult, arginfo::ArgInfo, sv::InferenceState) if res === :concrete_eval @@ -319,7 +293,6 @@ function CC.abstract_invoke(analyzer::JETAnalyzer, arginfo::ArgInfo, si::StmtInf end # report pass for undefined static parameter -@static if VERSION ≥ v"1.11.0-DEV.888" function CC.abstract_eval_statement_expr(analyzer::JETAnalyzer, e::Expr, vtypes::VarTable, sv::InferenceState) ret = @invoke CC.abstract_eval_statement_expr(analyzer::AbstractAnalyzer, e::Expr, vtypes::VarTable, sv::InferenceState) if e.head === :static_parameter @@ -327,15 +300,6 @@ function CC.abstract_eval_statement_expr(analyzer::JETAnalyzer, e::Expr, vtypes: end return ret end -else -function CC.abstract_eval_value_expr(analyzer::JETAnalyzer, e::Expr, vtypes::VarTable, sv::InferenceState) - ret = @invoke CC.abstract_eval_value_expr(analyzer::AbstractAnalyzer, e::Expr, vtypes::VarTable, sv::InferenceState) - if e.head === :static_parameter - ReportPass(analyzer)(UndefVarErrorReport, analyzer, sv, e.args[1]::Int) - end - return ret -end -end function CC.abstract_eval_special_value(analyzer::JETAnalyzer, @nospecialize(e), vtypes::VarTable, sv::InferenceState) @@ -361,9 +325,8 @@ end ret = @invoke CC.abstract_eval_basic_statement(analyzer::AbstractAnalyzer, stmt::Any, pc_vartable::VarTable, frame::InferenceState) if isexpr(stmt, :(=)) && (lhs = stmt.args[1]; isa(lhs, GlobalRef)) - rt = @static VERSION ≥ v"1.11.0-DEV.945" ? ret.rt : ret.type ReportPass(analyzer)(InvalidGlobalAssignmentError, analyzer, - frame, lhs.mod, lhs.name, rt) + frame, lhs.mod, lhs.name, ret.rt) end return ret end @@ -383,14 +346,12 @@ function CC.abstract_eval_value(analyzer::JETAnalyzer, @nospecialize(e), vtypes: return ret end -@static if VERSION ≥ v"1.11.0-DEV.1080" function CC.abstract_throw(analyzer::JETAnalyzer, argtypes::Vector{Any}, sv::InferenceState) ft = popfirst!(argtypes) ReportPass(analyzer)(SeriousExceptionReport, analyzer, sv, argtypes) pushfirst!(argtypes, ft) return @invoke CC.abstract_throw(analyzer::AbstractAnalyzer, argtypes::Vector{Any}, sv::InferenceState) end -end function CC.builtin_tfunction(analyzer::JETAnalyzer, @nospecialize(f), argtypes::Vector{Any}, sv::InferenceState) # `AbstractAnalyzer` isn't overloaded on `return_type` @@ -448,11 +409,7 @@ function (::SoundBasicPass)(::Type{GeneratorErrorReport}, analyzer::JETAnalyzer, CC.may_invoke_generator(mi) || return false world = get_inference_world(analyzer) try - @static if VERSION ≥ v"1.11-" @ccall jl_code_for_staged(mi::Any, world::UInt)::Any - else - @ccall jl_code_for_staged(mi::Any)::Any - end catch err # if user code throws error, wrap and report it report = add_new_report!(analyzer, result, GeneratorErrorReport(mi, err)) @@ -545,11 +502,7 @@ function report_uncaught_exceptions!(analyzer::JETAnalyzer, frame::InferenceStat throw_calls = nothing for (pc, stmt) in enumerate(stmts) isa(stmt, Expr) || continue - @static if VERSION ≥ v"1.11.0-DEV.888" - CC.is_throw_call(stmt, stmts) || continue - else - CC.is_throw_call(stmt) || continue - end + CC.is_throw_call(stmt, stmts) || continue # if this `throw` is already reported, don't duplicate if !isnothing(reported_locs) && linetable[codelocs[pc]]::LineInfoNode in reported_locs continue diff --git a/src/analyzers/optanalyzer.jl b/src/analyzers/optanalyzer.jl index e6f6c7242..7806ab7cc 100644 --- a/src/analyzers/optanalyzer.jl +++ b/src/analyzers/optanalyzer.jl @@ -181,20 +181,10 @@ struct OptAnalyzer{RP<:ReportPass,FF} <: AbstractAnalyzer function_filter::FF, skip_noncompileable_calls::Bool, skip_unoptimized_throw_blocks::Bool) where {RP<:ReportPass,FF} - if ((@static VERSION < v"1.11.0-DEV.1255" && true) && generating_output()) - # XXX Avoid storing analysis results into a cache that persists across the - # precompilation, as pkgimage currently doesn't support serializing - # externally created `CodeInstance`. Otherwise, `CodeInstance`s created by - # JET, containing JET-specific data structures, will leak into the native - # code cache, likely causing segfaults or undefined behavior. - # (see https://github.com/JuliaLang/julia/issues/48453). - analysis_cache = AnalysisCache() - else - cache_key = compute_hash(state.inf_params, state.opt_params, report_pass, - skip_noncompileable_calls, skip_unoptimized_throw_blocks) - cache_key = @invoke hash(function_filter::Any, cache_key::UInt) # HACK avoid dynamic dispatch - analysis_cache = get!(AnalysisCache, OPT_ANALYZER_CACHE, cache_key) - end + cache_key = compute_hash(state.inf_params, state.opt_params, report_pass, + skip_noncompileable_calls, skip_unoptimized_throw_blocks) + cache_key = @invoke hash(function_filter::Any, cache_key::UInt) # HACK avoid dynamic dispatch + analysis_cache = get!(AnalysisCache, OPT_ANALYZER_CACHE, cache_key) return new{RP,FF}(state, analysis_cache, report_pass, @@ -279,14 +269,12 @@ function CC.finish(frame::InferenceState, analyzer::OptAnalyzer) analyze = false end end - @static if VERSION ≥ v"1.11.0-DEV.404" if analyze && CC.is_result_constabi_eligible(frame.result) analyze = false # turn off optimization for this frame in order to achieve a minor perf gain, # similar to the effect of setting `may_discard_trees(::OptAnalyzer) = true` frame.result.src = nothing end - end push!(analyzer.__analyze_frame, analyze) if analyze diff --git a/test/analyzers/test_jetanalyzer.jl b/test/analyzers/test_jetanalyzer.jl index 83675cd4d..55556ffaf 100644 --- a/test/analyzers/test_jetanalyzer.jl +++ b/test/analyzers/test_jetanalyzer.jl @@ -1000,25 +1000,17 @@ end end # https://github.com/aviatesk/JET.jl/issues/311 - @static if VERSION ≥ v"1.11.0-DEV.753" - let result = report_call((Vector{Int},); mode=:sound) do xs - xs[5] - end - reports = get_reports_with_test(result) - @test length(reports) == 1 # bounds error check - end - let result = report_call((Vector{Any},); mode=:sound) do xs - xs[5] - end - reports = get_reports_with_test(result) - @test length(reports) == 2 # bounds error check + potential UndefRefError + let result = report_call((Vector{Int},); mode=:sound) do xs + xs[5] end - else - let result = report_call((Vector{Int},); mode=:sound) do xs - xs[5] - end - @test only(get_reports_with_test(result)) isa UnsoundBuiltinErrorReport + reports = get_reports_with_test(result) + @test length(reports) == 1 # bounds error check + end + let result = report_call((Vector{Any},); mode=:sound) do xs + xs[5] end + reports = get_reports_with_test(result) + @test length(reports) == 2 # bounds error check + potential UndefRefError end end @@ -1121,11 +1113,9 @@ test_call(Base.aligned_sizeof, (Union{DataType,Union},)) @test Base.return_types(; interp=JET.JETAnalyzer()) do Val(fieldcount(Int)) end |> only === Val{0} -let n = @static VERSION ≥ v"1.11.0-DEV.753" ? 2 : 0 - @test Base.return_types(; interp=JET.JETAnalyzer()) do - Val(fieldcount(Vector)) - end |> only === Val{n} -end +@test Base.return_types(; interp=JET.JETAnalyzer()) do + Val(fieldcount(Vector)) +end |> only === Val{2} struct CheckFieldIndex; a; end @test Base.return_types(; interp=JET.JETAnalyzer()) do Val(Base.fieldindex(CheckFieldIndex, :a)) @@ -1136,7 +1126,6 @@ end |> only === Val{3} @test_call sort([1,2,3]) @test_call sort!([1,2,3]) # aviatesk/JET.jl#669 -@static if VERSION ≥ v"1.11-" struct Point669{dim,T} coord::NTuple{dim,T} end @@ -1145,7 +1134,6 @@ f669(p) = getcoordinate669.(p) let pts = Point669.(rand(NTuple{2,Float64}, 10)) @test_call f669(pts) end -end # @static if VERSION ≥ v"1.11-" @test isconcretetype(only(Base.return_types(pairs, (@NamedTuple{kw1::Int,kw2::String},); interp=JET.JETAnalyzer()))) diff --git a/test/self_check.jl b/test/self_check.jl index 332b942de..32b426666 100644 --- a/test/self_check.jl +++ b/test/self_check.jl @@ -23,7 +23,7 @@ let target_modules = (JET,) # optimization analysis # ===================== - @static VERSION ≥ v"1.11-" && return # FIXME v1.11 + return # FIXME on v1.11 and higher # ignore some dynamically-designed functions # TODO implement `signature_filter` and limit the ignorance scope diff --git a/test/test_misc.jl b/test/test_misc.jl index 1391b7e99..b7942f098 100644 --- a/test/test_misc.jl +++ b/test/test_misc.jl @@ -50,11 +50,7 @@ end end using JET: process_config_dict -@static if VERSION ≥ v"1.11-" - using TOML: TOML -else - using Base.TOML: TOML -end +using TOML: TOML macro toml_str(s); TOML.parse(TOML.Parser(s)); end @testset "`process_config_dict`" begin diff --git a/test/toplevel/test_virtualprocess.jl b/test/toplevel/test_virtualprocess.jl index 305c4c406..7707eee34 100644 --- a/test/toplevel/test_virtualprocess.jl +++ b/test/toplevel/test_virtualprocess.jl @@ -888,7 +888,7 @@ end end # public - @static VERSION ≥ v"1.11-" && let res = report_text( + let res = report_text( """ module PublicTest public getx @@ -2238,11 +2238,7 @@ end @test 1234 === @test_nowarn(1234) @test 5678 === @test_warn("WARNING: foo", begin println(stderr, "WARNING: foo"); 5678; end) let a - @static if VERSION ≥ v"1.11.0-DEV.867" - @test_throws UndefVarError(:a, :local) a - else - @test_throws UndefVarError(:a) a - end + @test_throws UndefVarError(:a, :local) a @test_nowarn a = 1 @test a === 1 end