From 3fc4f6bb243cb623636f276cb143cf5c476bbc59 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Fri, 8 Sep 2023 20:54:17 -0400 Subject: [PATCH 01/15] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the=20Do?= =?UTF-8?q?wnloads=20stdlib=20from=20f97c72f=20to=208a614d5=20(#51246)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: Downloads URL: https://github.com/JuliaLang/Downloads.jl.git Stdlib branch: master Julia branch: master Old commit: f97c72f New commit: 8a614d5 Julia version: 1.11.0-DEV Downloads version: 1.6.0(It's okay that it doesn't match) Bump invoked by: @DilumAluthge Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaLang/Downloads.jl/compare/f97c72fbd726e208a04c53791b35cc34c747569f...8a614d592810b15d17885838dec61da244a12e09 ``` $ git log --oneline f97c72f..8a614d5 8a614d5 Skip flakey "concurrent requests" tests on windows (#228) 246504e add a small precompile workload (#226) 3ed0f08 Document how to bypass the 20-second timeout (#222) ``` Co-authored-by: Dilum Aluthge --- .../md5 | 1 + .../sha512 | 1 + .../md5 | 1 - .../sha512 | 1 - stdlib/Downloads.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/Downloads-8a614d592810b15d17885838dec61da244a12e09.tar.gz/md5 create mode 100644 deps/checksums/Downloads-8a614d592810b15d17885838dec61da244a12e09.tar.gz/sha512 delete mode 100644 deps/checksums/Downloads-f97c72fbd726e208a04c53791b35cc34c747569f.tar.gz/md5 delete mode 100644 deps/checksums/Downloads-f97c72fbd726e208a04c53791b35cc34c747569f.tar.gz/sha512 diff --git a/deps/checksums/Downloads-8a614d592810b15d17885838dec61da244a12e09.tar.gz/md5 b/deps/checksums/Downloads-8a614d592810b15d17885838dec61da244a12e09.tar.gz/md5 new file mode 100644 index 0000000000000..d59a1fcc37890 --- /dev/null +++ b/deps/checksums/Downloads-8a614d592810b15d17885838dec61da244a12e09.tar.gz/md5 @@ -0,0 +1 @@ +e88a4630ab5cd62b1d2a6213cd2942b8 diff --git a/deps/checksums/Downloads-8a614d592810b15d17885838dec61da244a12e09.tar.gz/sha512 b/deps/checksums/Downloads-8a614d592810b15d17885838dec61da244a12e09.tar.gz/sha512 new file mode 100644 index 0000000000000..af6d2ecf264ac --- /dev/null +++ b/deps/checksums/Downloads-8a614d592810b15d17885838dec61da244a12e09.tar.gz/sha512 @@ -0,0 +1 @@ +988a20fdd50c11dd66318d00032f14ae4c8b7809b507639d9907744cfdd0cff75c299ac67f99e62c25f527de1557ea6f736ee54ef18f2c54fbee76035de88aa5 diff --git a/deps/checksums/Downloads-f97c72fbd726e208a04c53791b35cc34c747569f.tar.gz/md5 b/deps/checksums/Downloads-f97c72fbd726e208a04c53791b35cc34c747569f.tar.gz/md5 deleted file mode 100644 index 4e70641a4a08b..0000000000000 --- a/deps/checksums/Downloads-f97c72fbd726e208a04c53791b35cc34c747569f.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -fa2c90db0e7aa73186c491aa2f03bb2b diff --git a/deps/checksums/Downloads-f97c72fbd726e208a04c53791b35cc34c747569f.tar.gz/sha512 b/deps/checksums/Downloads-f97c72fbd726e208a04c53791b35cc34c747569f.tar.gz/sha512 deleted file mode 100644 index 3f54f39d35ac6..0000000000000 --- a/deps/checksums/Downloads-f97c72fbd726e208a04c53791b35cc34c747569f.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -d36737b946af5e720402ce4f25e4c69c740bdbdc174385d6448c3660b26fffe34c14af7c4dd4d26ad864ad12771cabdf922c8b3cf4423167a46cdf3001ede125 diff --git a/stdlib/Downloads.version b/stdlib/Downloads.version index c6db08779e947..c5bd4d7a0d473 100644 --- a/stdlib/Downloads.version +++ b/stdlib/Downloads.version @@ -1,4 +1,4 @@ DOWNLOADS_BRANCH = master -DOWNLOADS_SHA1 = f97c72fbd726e208a04c53791b35cc34c747569f +DOWNLOADS_SHA1 = 8a614d592810b15d17885838dec61da244a12e09 DOWNLOADS_GIT_URL := https://github.com/JuliaLang/Downloads.jl.git DOWNLOADS_TAR_URL = https://api.github.com/repos/JuliaLang/Downloads.jl/tarball/$1 From 80603a418c27a06c76b2abaaf98d0be05bb66e05 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Sat, 9 Sep 2023 10:44:56 +0900 Subject: [PATCH 02/15] mark return type of failed concrete eval of intrinsics as `Bottom` (#51251) Because of the consistency assumed by `is_pure_intrinsic_infer`, we can aggressively mark the return type as `Bottom` in a case when the concrete evaluation of an intrinsic fails. --- base/compiler/tfuncs.jl | 3 ++- test/compiler/inference.jl | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/base/compiler/tfuncs.jl b/base/compiler/tfuncs.jl index 23be0015b5951..39c930e8cfbeb 100644 --- a/base/compiler/tfuncs.jl +++ b/base/compiler/tfuncs.jl @@ -2453,11 +2453,12 @@ function builtin_tfunction(interp::AbstractInterpreter, @nospecialize(f), argtyp try return Const(f(argvals...)) catch + return Bottom end end iidx = Int(reinterpret(Int32, f::IntrinsicFunction)) + 1 if iidx < 0 || iidx > length(T_IFUNC) - # invalid intrinsic + # unknown intrinsic return Any end tf = T_IFUNC[iidx] diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index b5f74dbc37520..79dc6838a86fc 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -5185,3 +5185,8 @@ end end foo51090(b) = return bar51090(b) @test !fully_eliminated(foo51090, (Int,)) + +# exploit throwness from concrete eval for intrinsics +@test Base.return_types() do + Base.or_int(true, 1) +end |> only === Union{} From 4c024e63c1b997f0f9d7f835f117b65d483f8956 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Sat, 9 Sep 2023 10:47:02 +0900 Subject: [PATCH 03/15] optimizer: code quality and performance improvements to post-opt analysis (#51211) This PR is composed of a set of fixes and improvements to `ipo_dataflow_analysis!`. I will rebase this once we merge #51185 and #51188, so still WIP, but let's see benchmark. @nanosoldier `runbenchmarks("inference", vs=":master")` --------- Co-authored-by: Keno Fischer --- base/compiler/optimize.jl | 167 ++++++++++++++++++-------------- base/compiler/ssair/irinterp.jl | 9 +- base/compiler/typeinfer.jl | 2 - 3 files changed, 100 insertions(+), 78 deletions(-) diff --git a/base/compiler/optimize.jl b/base/compiler/optimize.jl index f232094da3aff..6cfedfde7de94 100644 --- a/base/compiler/optimize.jl +++ b/base/compiler/optimize.jl @@ -483,13 +483,12 @@ end function conditional_successors_may_throw(lazypostdomtree::LazyPostDomtree, ir::IRCode, bb::Int) visited = BitSet((bb,)) worklist = Int[bb] - postdomtree = get!(lazypostdomtree) while !isempty(worklist) thisbb = pop!(worklist) for succ in ir.cfg.blocks[thisbb].succs succ in visited && continue push!(visited, succ) - postdominates(postdomtree, succ, thisbb) && continue + postdominates(get!(lazypostdomtree), succ, thisbb) && continue any_stmt_may_throw(ir, succ) && return true push!(worklist, succ) end @@ -502,54 +501,75 @@ struct AugmentedDomtree domtree::DomTree end +mutable struct LazyAugmentedDomtree + ir::IRCode + agdomtree::AugmentedDomtree + LazyAugmentedDomtree(ir::IRCode) = new(ir) +end + +function get!(lazyagdomtree::LazyAugmentedDomtree) + isdefined(lazyagdomtree, :agdomtree) && return lazyagdomtree.agdomtree + ir = lazyagdomtree.ir + cfg = copy(ir.cfg) + # Add a virtual basic block to represent the exit + push!(cfg.blocks, BasicBlock(StmtRange(0:-1))) + for bb = 1:(length(cfg.blocks)-1) + terminator = ir[SSAValue(last(cfg.blocks[bb].stmts))][:inst] + if isa(terminator, ReturnNode) && isdefined(terminator, :val) + cfg_insert_edge!(cfg, bb, length(cfg.blocks)) + end + end + domtree = construct_domtree(cfg.blocks) + return lazyagdomtree.agdomtree = AugmentedDomtree(cfg, domtree) +end + +# TODO refine `:effect_free` using EscapeAnalysis +mutable struct PostOptAnalysisState + all_retpaths_consistent::Bool + all_effect_free::Bool + all_nothrow::Bool + all_noub::Bool + any_conditional_ub::Bool + PostOptAnalysisState() = new(true, true, true, true, false) +end +give_up_refinements!(sv::PostOptAnalysisState) = + sv.all_retpaths_consistent = sv.all_effect_free = sv.all_nothrow = sv.all_noub = false +function any_refinable(sv::PostOptAnalysisState, effects::Effects) + return ((!is_consistent(effects) & sv.all_retpaths_consistent) | + (!is_effect_free(effects) & sv.all_effect_free) | + (!is_nothrow(effects) & sv.all_nothrow) | + (!is_noub(effects) & sv.all_noub)) +end + +function refine_effects!(result::InferenceResult, sv::PostOptAnalysisState) + effects = result.ipo_effects + return result.ipo_effects = Effects(effects; + consistent = sv.all_retpaths_consistent ? ALWAYS_TRUE : effects.consistent, + effect_free = sv.all_effect_free ? ALWAYS_TRUE : effects.effect_free, + nothrow = sv.all_nothrow ? true : effects.nothrow, + noub = sv.all_noub ? (sv.any_conditional_ub ? NOUB_IF_NOINBOUNDS : ALWAYS_TRUE) : effects.noub) +end + function is_ipo_dataflow_analysis_profitable(effects::Effects) return !(is_consistent(effects) && is_effect_free(effects) && is_nothrow(effects) && is_noub(effects)) end function ipo_dataflow_analysis!(interp::AbstractInterpreter, ir::IRCode, result::InferenceResult) - effects = result.ipo_effects - if !is_ipo_dataflow_analysis_profitable(effects) - return effects + if !is_ipo_dataflow_analysis_profitable(result.ipo_effects) + return result.ipo_effects end inconsistent = BitSetBoundedMinPrioritySet(length(ir.stmts)) - inconsistent_bbs = BitSet() tpdum = TwoPhaseDefUseMap(length(ir.stmts)) lazypostdomtree = LazyPostDomtree(ir) + lazyagdomtree = LazyAugmentedDomtree(ir) - all_effect_free = true # TODO refine using EscapeAnalysis - all_nothrow = true - all_retpaths_consistent = true - all_noub = true - any_conditional_ub = false - had_trycatch = false + sv = PostOptAnalysisState() scanner = BBScanner(ir) - agdomtree = nothing - function get_augmented_domtree() - if agdomtree !== nothing - return agdomtree - end - cfg = copy(ir.cfg) - # Add a virtual basic block to represent the exit - push!(cfg.blocks, BasicBlock(StmtRange(0:-1))) - - for bb = 1:(length(cfg.blocks)-1) - terminator = ir[SSAValue(last(cfg.blocks[bb].stmts))][:inst] - if isa(terminator, ReturnNode) && isdefined(terminator, :val) - cfg_insert_edge!(cfg, bb, length(cfg.blocks)) - end - end - - domtree = construct_domtree(cfg.blocks) - agdomtree = AugmentedDomtree(cfg, domtree) - return agdomtree - end - - function is_getfield_with_boundscheck_arg(inst::Instruction) - stmt = inst[:stmt] + function is_getfield_with_boundscheck_arg(@nospecialize stmt) is_known_call(stmt, getfield, ir) || return false length(stmt.args) < 4 && return false boundscheck = stmt.args[end] @@ -560,13 +580,14 @@ function ipo_dataflow_analysis!(interp::AbstractInterpreter, ir::IRCode, result: function is_conditional_noub(inst::Instruction) # Special case: `:boundscheck` into `getfield` - is_getfield_with_boundscheck_arg(inst) || return false - barg = inst[:stmt].args[end] + stmt = inst[:stmt] + is_getfield_with_boundscheck_arg(stmt) || return false + barg = stmt.args[end] bstmt = ir[barg][:stmt] isexpr(bstmt, :boundscheck) || return false # If IR_FLAG_INBOUNDS is already set, no more conditional ub - (length(bstmt.args) != 0 && bstmt.args[1] === false) && return false - any_conditional_ub = true + (!isempty(bstmt.args) && bstmt.args[1] === false) && return false + sv.any_conditional_ub = true return true end @@ -577,22 +598,22 @@ function ipo_dataflow_analysis!(interp::AbstractInterpreter, ir::IRCode, result: # ignore control flow node – they are not removable on their own and thus not # have `IR_FLAG_EFFECT_FREE` but still do not taint `:effect_free`-ness of # the whole method invocation - all_effect_free &= (flag & IR_FLAG_EFFECT_FREE) != 0 + sv.all_effect_free &= !iszero(flag & IR_FLAG_EFFECT_FREE) end - all_nothrow &= (flag & IR_FLAG_NOTHROW) != 0 - if (flag & IR_FLAG_NOUB) == 0 + sv.all_nothrow &= !iszero(flag & IR_FLAG_NOTHROW) + if iszero(flag & IR_FLAG_NOUB) if !is_conditional_noub(inst) - all_noub = false + sv.all_noub = false end end end function scan_inconsistency!(inst::Instruction, idx::Int) flag = inst[:flag] - stmt_inconsistent = (flag & IR_FLAG_CONSISTENT) == 0 + stmt_inconsistent = iszero(flag & IR_FLAG_CONSISTENT) stmt = inst[:stmt] # Special case: For getfield, we allow inconsistency of the :boundscheck argument - if is_getfield_with_boundscheck_arg(inst) + if is_getfield_with_boundscheck_arg(stmt) for i = 1:(length(stmt.args)-1) val = stmt.args[i] if isa(val, SSAValue) @@ -613,39 +634,40 @@ function ipo_dataflow_analysis!(interp::AbstractInterpreter, ir::IRCode, result: return stmt_inconsistent end - function scan_stmt!(inst, idx, lstmt, bb) + function scan_stmt!(inst::Instruction, idx::Int, lstmt::Int, bb::Int) stmt = inst[:inst] flag = inst[:flag] if isexpr(stmt, :enter) # try/catch not yet modeled - had_trycatch = true - return false + give_up_refinements!(sv) + return nothing end scan_non_dataflow_flags!(inst) + stmt_inconsistent = scan_inconsistency!(inst, idx) - if idx == lstmt - if isa(stmt, ReturnNode) && isdefined(stmt, :val) && stmt_inconsistent - all_retpaths_consistent = false - elseif isa(stmt, GotoIfNot) && stmt_inconsistent + if stmt_inconsistent && idx == lstmt + if isa(stmt, ReturnNode) && isdefined(stmt, :val) + sv.all_retpaths_consistent = false + elseif isa(stmt, GotoIfNot) # Conditional Branch with inconsistent condition. # If we do not know this function terminates, taint consistency, now, # :consistent requires consistent termination. TODO: Just look at the # inconsistent region. if !result.ipo_effects.terminates - all_retpaths_consistent = false - # Check if there are potential throws that require + sv.all_retpaths_consistent = false elseif conditional_successors_may_throw(lazypostdomtree, ir, bb) - all_retpaths_consistent = false + # Check if there are potential throws that require + sv.all_retpaths_consistent = false else - (; cfg, domtree) = get_augmented_domtree() + (; cfg, domtree) = get!(lazyagdomtree) for succ in iterated_dominance_frontier(cfg, BlockLiveness(ir.cfg.blocks[bb].succs, nothing), domtree) if succ == length(cfg.blocks) # Phi node in the virtual exit -> We have a conditional # return. TODO: Check if all the retvals are egal. - all_retpaths_consistent = false + sv.all_retpaths_consistent = false else visit_bb_phis!(ir, succ) do phiidx::Int push!(inconsistent, phiidx) @@ -656,26 +678,31 @@ function ipo_dataflow_analysis!(interp::AbstractInterpreter, ir::IRCode, result: end end + # bail out early if there are no possibilities to refine the effects + if !any_refinable(sv, result.ipo_effects) + return nothing + end + return true end completed_scan = scan!(scan_stmt!, scanner, true) - effects = result.ipo_effects - if completed_scan - had_trycatch && return effects - else - if !all_retpaths_consistent + if !completed_scan + if !sv.all_retpaths_consistent # No longer any dataflow concerns, just scan the flags scan!(scanner, false) do inst::Instruction, idx::Int, lstmt::Int, bb::Int scan_non_dataflow_flags!(inst) + # bail out early if there are no possibilities to refine the effects + if !any_refinable(sv, result.ipo_effects) + return nothing + end return true end else scan!(scan_stmt!, scanner, true) complete!(tpdum); push!(scanner.bb_ip, 1) populate_def_use_map!(tpdum, scanner) - stmt_ip = BitSetBoundedMinPrioritySet(length(ir.stmts)) for def in inconsistent for use in tpdum[def] @@ -689,7 +716,7 @@ function ipo_dataflow_analysis!(interp::AbstractInterpreter, ir::IRCode, result: idx = popfirst!(stmt_ip) inst = ir[SSAValue(idx)] stmt = inst[:inst] - if is_getfield_with_boundscheck_arg(inst) + if is_getfield_with_boundscheck_arg(stmt) any_non_boundscheck_inconsistent = false for i = 1:(length(stmt.args)-1) val = stmt.args[i] @@ -700,30 +727,26 @@ function ipo_dataflow_analysis!(interp::AbstractInterpreter, ir::IRCode, result: end any_non_boundscheck_inconsistent || continue elseif isa(stmt, ReturnNode) - all_retpaths_consistent = false + sv.all_retpaths_consistent = false else isa(stmt, GotoIfNot) bb = block_for_inst(ir, idx) blockliveness = BlockLiveness(ir.cfg.blocks[bb].succs, nothing) domtree = construct_domtree(ir.cfg.blocks) for succ in iterated_dominance_frontier(ir.cfg, blockliveness, domtree) - visit_bb_phis!(ir, succ) do phiidx + visit_bb_phis!(ir, succ) do phiidx::Int push!(inconsistent, phiidx) push!(stmt_ip, phiidx) end end end - all_retpaths_consistent || break + sv.all_retpaths_consistent || break append!(inconsistent, tpdum[idx]) append!(stmt_ip, tpdum[idx]) end end end - return result.ipo_effects = Effects(effects; - consistent = all_retpaths_consistent ? ALWAYS_TRUE : effects.consistent, - effect_free = all_effect_free ? ALWAYS_TRUE : effects.effect_free, - nothrow = all_nothrow ? true : effects.nothrow, - noub = all_noub ? (any_conditional_ub ? NOUB_IF_NOINBOUNDS : ALWAYS_TRUE) : effects.noub) + return refine_effects!(result, sv) end # run the optimization work diff --git a/base/compiler/ssair/irinterp.jl b/base/compiler/ssair/irinterp.jl index 608fe4d915c6c..233310e44626c 100644 --- a/base/compiler/ssair/irinterp.jl +++ b/base/compiler/ssair/irinterp.jl @@ -227,7 +227,8 @@ function scan!(callback, scanner::BBScanner, forwards_only::Bool) for idx = stmts inst = ir[SSAValue(idx)] ret = callback(inst, idx, lstmt, bb) - ret === false && break + ret === nothing && return true + ret::Bool || break idx == lstmt && process_terminator!(inst[:inst], bb, bb_ip) && forwards_only && return false end end @@ -235,7 +236,7 @@ function scan!(callback, scanner::BBScanner, forwards_only::Bool) end function populate_def_use_map!(tpdum::TwoPhaseDefUseMap, scanner::BBScanner) - scan!(scanner, false) do inst, idx, lstmt, bb + scan!(scanner, false) do inst::Instruction, idx::Int, lstmt::Int, bb::Int for ur in userefs(inst) val = ur[] if isa(val, SSAValue) @@ -262,7 +263,7 @@ function _ir_abstract_constant_propagation(interp::AbstractInterpreter, irsv::IR # Fast path: Scan both use counts and refinement in one single pass of # of the instructions. In the absence of backedges, this will # converge. - completed_scan = scan!(scanner, true) do inst, idx, lstmt, bb + completed_scan = scan!(scanner, true) do inst::Instruction, idx::Int, lstmt::Int, bb::Int irsv.curridx = idx stmt = ir.stmts[idx][:inst] typ = ir.stmts[idx][:type] @@ -315,7 +316,7 @@ function _ir_abstract_constant_propagation(interp::AbstractInterpreter, irsv::IR stmt_ip = BitSetBoundedMinPrioritySet(length(ir.stmts)) # Slow Path Phase 1.A: Complete use scanning - scan!(scanner, false) do inst, idx, lstmt, bb + scan!(scanner, false) do inst::Instruction, idx::Int, lstmt::Int, bb::Int irsv.curridx = idx stmt = inst[:inst] flag = inst[:flag] diff --git a/base/compiler/typeinfer.jl b/base/compiler/typeinfer.jl index f4ea69b310415..e4f143e0c75b6 100644 --- a/base/compiler/typeinfer.jl +++ b/base/compiler/typeinfer.jl @@ -464,7 +464,6 @@ function adjust_effects(ipo_effects::Effects, def::Method) return ipo_effects end - function adjust_effects(sv::InferenceState) ipo_effects = sv.ipo_effects @@ -554,7 +553,6 @@ function finish(me::InferenceState, interp::AbstractInterpreter) me.result.result = bestguess me.ipo_effects = me.result.ipo_effects = adjust_effects(me) - if limited_ret # a parent may be cached still, but not this intermediate work: # we can throw everything else away now From 43638959a45fca0cb86f9c334a508f14ffe712ce Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sat, 9 Sep 2023 02:28:00 -0400 Subject: [PATCH 04/15] Unify flags_for_effects handling (#51238) There was two places where we were turning Effects into flags, one in the optimizer, one in inference. Unify these two both use the same function, but we need to refactor a bit to make sure all the effects get passed to the correct place. --------- Co-authored-by: Shuhei Kadowaki --- base/compiler/abstractinterpretation.jl | 124 +++++++++++++----------- base/compiler/effects.jl | 9 +- base/compiler/inferencestate.jl | 16 ++- base/compiler/optimize.jl | 6 +- base/compiler/ssair/passes.jl | 2 +- base/compiler/ssair/verify.jl | 1 + test/compiler/effects.jl | 5 + 7 files changed, 104 insertions(+), 59 deletions(-) diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index e3e38ba4afef2..29dbd0e8c05f8 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -2197,32 +2197,6 @@ function abstract_eval_cfunction(interp::AbstractInterpreter, e::Expr, vtypes::U nothing end -function abstract_eval_value_expr(interp::AbstractInterpreter, e::Expr, vtypes::Union{VarTable,Nothing}, sv::AbsIntState) - head = e.head - if head === :static_parameter - n = e.args[1]::Int - nothrow = false - if 1 <= n <= length(sv.sptypes) - sp = sv.sptypes[n] - rt = sp.typ - nothrow = !sp.undef - else - rt = Any - end - merge_effects!(interp, sv, Effects(EFFECTS_TOTAL; nothrow)) - return rt - elseif head === :boundscheck - merge_effects!(interp, sv, Effects(EFFECTS_TOTAL; consistent = ALWAYS_FALSE)) - return Bool - elseif head === :inbounds - @assert false "Expected `:inbounds` expression to have been moved into SSA flags" - elseif head === :the_exception - merge_effects!(interp, sv, Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE)) - return Any - end - return Any -end - function abstract_eval_special_value(interp::AbstractInterpreter, @nospecialize(e), vtypes::Union{VarTable,Nothing}, sv::AbsIntState) if isa(e, QuoteNode) return Const(e.value) @@ -2252,6 +2226,34 @@ function abstract_eval_special_value(interp::AbstractInterpreter, @nospecialize( return Const(e) end +function abstract_eval_value_expr(interp::AbstractInterpreter, e::Expr, vtypes::Union{VarTable,Nothing}, sv::AbsIntState) + head = e.head + if head === :static_parameter + n = e.args[1]::Int + nothrow = false + if 1 <= n <= length(sv.sptypes) + sp = sv.sptypes[n] + rt = sp.typ + nothrow = !sp.undef + else + rt = Any + end + merge_effects!(interp, sv, Effects(EFFECTS_TOTAL; nothrow)) + return rt + elseif head === :call + # TODO: We still have non-linearized cglobal + @assert e.args[1] === Core.tuple || + e.args[1] === GlobalRef(Core, :tuple) + else + # Some of our tests expect us to handle invalid IR here and error later + # - permit that for now. + # @assert false "Unexpected EXPR head in value position" + merge_effects!(interp, sv, EFFECTS_UNKNOWN) + end + return Any +end + + function abstract_eval_value(interp::AbstractInterpreter, @nospecialize(e), vtypes::Union{VarTable,Nothing}, sv::AbsIntState) if isa(e, Expr) return abstract_eval_value_expr(interp, e, vtypes, sv) @@ -2280,38 +2282,12 @@ struct RTEffects RTEffects(@nospecialize(rt), effects::Effects) = new(rt, effects) end -function mark_curr_effect_flags!(sv::AbsIntState, effects::Effects) - if isa(sv, InferenceState) - if is_effect_free(effects) - add_curr_ssaflag!(sv, IR_FLAG_EFFECT_FREE) - else - sub_curr_ssaflag!(sv, IR_FLAG_EFFECT_FREE) - end - if is_nothrow(effects) - add_curr_ssaflag!(sv, IR_FLAG_NOTHROW) - else - sub_curr_ssaflag!(sv, IR_FLAG_NOTHROW) - end - if is_consistent(effects) - add_curr_ssaflag!(sv, IR_FLAG_CONSISTENT) - else - sub_curr_ssaflag!(sv, IR_FLAG_CONSISTENT) - end - if is_noub(effects, false) - add_curr_ssaflag!(sv, IR_FLAG_NOUB) - else - sub_curr_ssaflag!(sv, IR_FLAG_NOUB) - end - end -end - function abstract_call(interp::AbstractInterpreter, arginfo::ArgInfo, sv::InferenceState) si = StmtInfo(!call_result_unused(sv, sv.currpc)) (; rt, effects, info) = abstract_call(interp, arginfo, si, sv) sv.stmt_info[sv.currpc] = info # mark this call statement as DCE-elgible # TODO better to do this in a single pass based on the `info` object at the end of abstractinterpret? - mark_curr_effect_flags!(sv, effects) return RTEffects(rt, effects) end @@ -2451,7 +2427,6 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp elseif ehead === :foreigncall (; rt, effects) = abstract_eval_foreigncall(interp, e, vtypes, sv) t = rt - mark_curr_effect_flags!(sv, effects) elseif ehead === :cfunction effects = EFFECTS_UNKNOWN t = e.args[1] @@ -2485,12 +2460,16 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp t = Const(true) elseif InferenceParams(interp).assume_bindings_static t = Const(false) + else + effects = Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE) end elseif isa(sym, GlobalRef) if isdefined(sym.mod, sym.name) t = Const(true) elseif InferenceParams(interp).assume_bindings_static t = Const(false) + else + effects = Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE) end elseif isexpr(sym, :static_parameter) n = sym.args[1]::Int @@ -2502,6 +2481,8 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp t = Const(false) end end + else + effects = EFFECTS_UNKNOWN end elseif ehead === :throw_undef_if_not condt = argextype(stmt.args[2], ir) @@ -2517,12 +2498,44 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp elseif !hasintersect(windenconst(condt), Bool) t = Union{} end + elseif ehead === :boundscheck + t = Bool + effects = Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE) + elseif ehead === :the_exception + t = Any + effects = Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE) + elseif ehead === :static_parameter + n = e.args[1]::Int + nothrow = false + if 1 <= n <= length(sv.sptypes) + sp = sv.sptypes[n] + t = sp.typ + nothrow = !sp.undef + else + t = Any + end + effects = Effects(EFFECTS_TOTAL; nothrow) + elseif ehead === :gc_preserve_begin || ehead === :aliasscope + t = Any + effects = Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE, effect_free=EFFECT_FREE_GLOBALLY) + elseif ehead === :gc_preserve_end || ehead === :leave || ehead === :pop_exception || ehead === :global || ehead === :popaliasscope + t = Nothing + effects = Effects(EFFECTS_TOTAL; effect_free=EFFECT_FREE_GLOBALLY) + elseif ehead === :method + t = Method + effects = Effects(EFFECTS_TOTAL; effect_free=EFFECT_FREE_GLOBALLY) + elseif ehead === :thunk + t = Any + effects = EFFECTS_UNKNOWN elseif false @label always_throw t = Bottom effects = EFFECTS_THROWS else t = abstract_eval_value_expr(interp, e, vtypes, sv) + # N.B.: abstract_eval_value_expr can modify the global effects, but + # we move out any arguments with effects during SSA construction later + # and recompute the effects. effects = EFFECTS_TOTAL end return RTEffects(t, effects) @@ -2542,7 +2555,6 @@ function refine_partial_type(@nospecialize t) end function abstract_eval_foreigncall(interp::AbstractInterpreter, e::Expr, vtypes::Union{VarTable,Nothing}, sv::AbsIntState) - abstract_eval_value(interp, e.args[1], vtypes, sv) mi = frame_instance(sv) t = sp_type_rewrap(e.args[2], mi, true) for i = 3:length(e.args) @@ -2601,6 +2613,10 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e), effects = Effects(effects; noub=ALWAYS_TRUE) end end + # N.B.: This only applies to the effects of the statement itself. + # It is possible for arguments (GlobalRef/:static_parameter) to throw, + # but these will be recomputed during SSA construction later. + set_curr_ssaflag!(sv, flags_for_effects(effects), IR_FLAGS_EFFECTS) merge_effects!(interp, sv, effects) e = e::Expr @assert !isa(rt, TypeVar) "unhandled TypeVar" diff --git a/base/compiler/effects.jl b/base/compiler/effects.jl index efe22bb39bc24..d6cc7ee7378e1 100644 --- a/base/compiler/effects.jl +++ b/base/compiler/effects.jl @@ -131,7 +131,14 @@ const CONSISTENT_IF_NOTRETURNED = 0x01 << 1 const CONSISTENT_IF_INACCESSIBLEMEMONLY = 0x01 << 2 # :effect_free-ness bits -const EFFECT_FREE_IF_INACCESSIBLEMEMONLY = 0x01 << 1 +const EFFECT_FREE_IF_INACCESSIBLEMEMONLY = 0x02 + +""" +`EFFECT_FREE_GLOBALLY` means that the statement is `:effect-free` and does not have a +caller-visible effect, but may not be removed from the function itself. This may e.g. +be used for effects that last only for the scope of the current function. +""" +const EFFECT_FREE_GLOBALLY = 0x03 # :inaccessiblememonly bits const INACCESSIBLEMEM_OR_ARGMEMONLY = 0x01 << 1 diff --git a/base/compiler/inferencestate.jl b/base/compiler/inferencestate.jl index 67e653862b4b5..9571eff9134d6 100644 --- a/base/compiler/inferencestate.jl +++ b/base/compiler/inferencestate.jl @@ -817,14 +817,28 @@ end get_curr_ssaflag(sv::InferenceState) = sv.src.ssaflags[sv.currpc] get_curr_ssaflag(sv::IRInterpretationState) = sv.ir.stmts[sv.curridx][:flag] +function set_curr_ssaflag!(sv::InferenceState, flag::UInt32, mask::UInt32=typemax(UInt32)) + curr_flag = sv.src.ssaflags[sv.currpc] + sv.src.ssaflags[sv.currpc] = (curr_flag & ~mask) | flag +end +function set_curr_ssaflag!(sv::IRInterpretationState, flag::UInt32, mask::UInt32=typemax(UInt32)) + curr_flag = sv.ir.stmts[sv.curridx][:flag] + sv.ir.stmts[sv.curridx][:flag] = (curr_flag & ~mask) | flag +end + add_curr_ssaflag!(sv::InferenceState, flag::UInt32) = sv.src.ssaflags[sv.currpc] |= flag add_curr_ssaflag!(sv::IRInterpretationState, flag::UInt32) = sv.ir.stmts[sv.curridx][:flag] |= flag sub_curr_ssaflag!(sv::InferenceState, flag::UInt32) = sv.src.ssaflags[sv.currpc] &= ~flag sub_curr_ssaflag!(sv::IRInterpretationState, flag::UInt32) = sv.ir.stmts[sv.curridx][:flag] &= ~flag -merge_effects!(::AbstractInterpreter, caller::InferenceState, effects::Effects) = +function merge_effects!(::AbstractInterpreter, caller::InferenceState, effects::Effects) + if effects.effect_free === EFFECT_FREE_GLOBALLY + # This tracks the global effects + effects = Effects(effects; effect_free=ALWAYS_TRUE) + end caller.ipo_effects = merge_effects(caller.ipo_effects, effects) +end merge_effects!(::AbstractInterpreter, ::IRInterpretationState, ::Effects) = return struct InferenceLoopState diff --git a/base/compiler/optimize.jl b/base/compiler/optimize.jl index 6cfedfde7de94..d2c0284fd173f 100644 --- a/base/compiler/optimize.jl +++ b/base/compiler/optimize.jl @@ -39,6 +39,8 @@ const IR_FLAG_REFINED = UInt32(1) << 7 # This is :noub == ALWAYS_TRUE const IR_FLAG_NOUB = UInt32(1) << 8 +const IR_FLAGS_EFFECTS = IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW | IR_FLAG_CONSISTENT | IR_FLAG_NOUB + const TOP_TUPLE = GlobalRef(Core, :tuple) # This corresponds to the type of `CodeInfo`'s `inlining_cost` field @@ -333,9 +335,9 @@ function stmt_effect_flags(𝕃ₒ::AbstractLattice, @nospecialize(stmt), @nospe return (false, false, false) end return (false, true, true) - elseif head === :isdefined || head === :the_exception || head === :copyast || head === :inbounds + elseif head === :inbounds return (true, true, true) - elseif head === :boundscheck + elseif head === :boundscheck || head === :isdefined || head === :the_exception || head === :copyast return (false, true, true) else # e.g. :loopinfo diff --git a/base/compiler/ssair/passes.jl b/base/compiler/ssair/passes.jl index e972dd4af1720..362aefcde6026 100644 --- a/base/compiler/ssair/passes.jl +++ b/base/compiler/ssair/passes.jl @@ -953,7 +953,7 @@ end function refine_new_effects!(𝕃ₒ::AbstractLattice, compact::IncrementalCompact, idx::Int, stmt::Expr) inst = compact[SSAValue(idx)] - if !(iszero(inst[:flag] & IR_FLAG_NOTHROW) && iszero(inst[:flag] & IR_FLAG_EFFECT_FREE)) + if (inst[:flag] & (IR_FLAG_NOTHROW | IR_FLAG_EFFECT_FREE)) == (IR_FLAG_NOTHROW | IR_FLAG_EFFECT_FREE) return # already accurate end (consistent, effect_free_and_nothrow, nothrow) = new_expr_effect_flags(𝕃ₒ, stmt.args, compact, pattern_match_typeof) diff --git a/base/compiler/ssair/verify.jl b/base/compiler/ssair/verify.jl index f6b94eac53897..ade1104e08ec5 100644 --- a/base/compiler/ssair/verify.jl +++ b/base/compiler/ssair/verify.jl @@ -20,6 +20,7 @@ if !isdefined(@__MODULE__, Symbol("@verify_error")) end end +is_toplevel_expr_head(head::Symbol) = head === :global || head === :method || head === :thunk is_value_pos_expr_head(head::Symbol) = head === :static_parameter function check_op(ir::IRCode, domtree::DomTree, @nospecialize(op), use_bb::Int, use_idx::Int, printed_use_idx::Int, print::Bool, isforeigncall::Bool, arg_idx::Int, allow_frontend_forms::Bool) if isa(op, SSAValue) diff --git a/test/compiler/effects.jl b/test/compiler/effects.jl index 17b34401405bb..94eb46ee7810a 100644 --- a/test/compiler/effects.jl +++ b/test/compiler/effects.jl @@ -1001,6 +1001,11 @@ isassigned_effects(s) = isassigned(Ref(s)) isassigned_effects(:foo) end +# :isdefined effects +@test @eval Base.infer_effects() do + @isdefined($(gensym("some_undef_symbol"))) +end |> !Core.Compiler.is_consistent + # Effects of Base.hasfield (#50198) hf50198(s) = hasfield(typeof((;x=1, y=2)), s) f50198() = (hf50198(Ref(:x)[]); nothing) From 4c3aaa2b34996708367f9d5e4472fb5a1062bf63 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Sat, 9 Sep 2023 16:53:44 +0900 Subject: [PATCH 05/15] reflection: define `Base.generating_output` utility function (#51216) And replaces `ccall(:jl_generating_out, ...)` with the new function. --------- Co-authored-by: Jameson Nash --- base/compiler/typeinfer.jl | 6 ++---- base/compiler/utilities.jl | 2 +- base/loading.jl | 8 ++++---- base/reflection.jl | 19 +++++++++++++++++++ stdlib/Profile/src/precompile.jl | 2 +- stdlib/REPL/src/REPLCompletions.jl | 2 +- 6 files changed, 28 insertions(+), 11 deletions(-) diff --git a/base/compiler/typeinfer.jl b/base/compiler/typeinfer.jl index e4f143e0c75b6..343e902e30213 100644 --- a/base/compiler/typeinfer.jl +++ b/base/compiler/typeinfer.jl @@ -805,8 +805,6 @@ function resolve_call_cycle!(interp::AbstractInterpreter, mi::MethodInstance, pa return false end -generating_sysimg() = ccall(:jl_generating_output, Cint, ()) != 0 && JLOptions().incremental == 0 - ipo_effects(code::CodeInstance) = decode_effects(code.ipo_purity_bits) struct EdgeCallResult @@ -840,7 +838,7 @@ function typeinf_edge(interp::AbstractInterpreter, method::Method, @nospecialize else cache = :global # cache edge targets by default end - if ccall(:jl_get_module_infer, Cint, (Any,), method.module) == 0 && !generating_sysimg() + if ccall(:jl_get_module_infer, Cint, (Any,), method.module) == 0 && !generating_output(#=incremental=#false) add_remark!(interp, caller, "Inference is disabled for the target module") return EdgeCallResult(Any, nothing, Effects()) end @@ -1011,7 +1009,7 @@ function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance) return inf end end - if ccall(:jl_get_module_infer, Cint, (Any,), method.module) == 0 && !generating_sysimg() + if ccall(:jl_get_module_infer, Cint, (Any,), method.module) == 0 && !generating_output(#=incremental=#false) return retrieve_code_info(mi, get_world_counter(interp)) end lock_mi_inference(interp, mi) diff --git a/base/compiler/utilities.jl b/base/compiler/utilities.jl index e85605b55b6eb..bdc0156efd824 100644 --- a/base/compiler/utilities.jl +++ b/base/compiler/utilities.jl @@ -500,7 +500,7 @@ is_root_module(m::Module) = false inlining_enabled() = (JLOptions().can_inline == 1) function coverage_enabled(m::Module) - ccall(:jl_generating_output, Cint, ()) == 0 || return false # don't alter caches + generating_output() && return false # don't alter caches cov = JLOptions().code_coverage if cov == 1 # user m = moduleroot(m) diff --git a/base/loading.jl b/base/loading.jl index b7fe40bf01ccb..1cfb33fe6a853 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -1703,7 +1703,7 @@ If a module or file is *not* safely precompilable, it should call `__precompile_ order to throw an error if Julia attempts to precompile it. """ @noinline function __precompile__(isprecompilable::Bool=true) - if !isprecompilable && ccall(:jl_generating_output, Cint, ()) != 0 + if !isprecompilable && generating_output() throw(PrecompilableError()) end nothing @@ -1843,7 +1843,7 @@ root_module_key(m::Module) = @lock require_lock module_keys[m] if haskey(loaded_modules, key) oldm = loaded_modules[key] if oldm !== m - if (0 != ccall(:jl_generating_output, Cint, ())) && (JLOptions().incremental != 0) + if generating_output(#=incremental=#true) error("Replacing module `$(key.name)`") else @warn "Replacing module `$(key.name)`" @@ -1894,7 +1894,7 @@ function set_pkgorigin_version_path(pkg::PkgId, path::Union{String,Nothing}) pkgorigin = get!(PkgOrigin, pkgorigins, pkg) if path !== nothing # Pkg needs access to the version of packages in the sysimage. - if Core.Compiler.generating_sysimg() + if generating_output(#=incremental=#false) pkgorigin.version = get_pkgversion_from_path(joinpath(dirname(path), "..")) end end @@ -1949,7 +1949,7 @@ function _require(pkg::PkgId, env=nothing) end if JLOptions().use_compiled_modules == 1 - if (0 == ccall(:jl_generating_output, Cint, ())) || (JLOptions().incremental != 0) + if !generating_output(#=incremental=#false) if !pkg_precompile_attempted && isinteractive() && isassigned(PKG_PRECOMPILE_HOOK) pkg_precompile_attempted = true unlock(require_lock) diff --git a/base/reflection.jl b/base/reflection.jl index 8a74099039da5..2cda541bd5a4f 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -2346,3 +2346,22 @@ function destructure_callex(topmod::Module, @nospecialize(ex)) end return f, args, kwargs end + +""" + Base.generating_output([incremental::Bool])::Bool + +Return `true` if the current process is being used to pre-generate a +code cache via any of the `--output-*` command line arguments. The +optional argument `incremental` controls whether to only return `true` +for that specific mode of compilation. + +!!! compat "Julia 1.11" + This function requires at least Julia 1.11. +""" +function generating_output(incremental::Union{Bool,Nothing}=nothing) + ccall(:jl_generating_output, Cint, ()) == 0 && return false + if incremental !== nothing + JLOptions().incremental == incremental || return false + end + return true +end diff --git a/stdlib/Profile/src/precompile.jl b/stdlib/Profile/src/precompile.jl index 2d947429861a9..7b33e09941b28 100644 --- a/stdlib/Profile/src/precompile.jl +++ b/stdlib/Profile/src/precompile.jl @@ -1,4 +1,4 @@ -if ccall(:jl_generating_output, Cint, ()) == 1 +if Base.generating_output() precompile(Tuple{typeof(Profile.tree!), Profile.StackFrameTree{UInt64}, Vector{UInt64}, Dict{UInt64, Vector{Base.StackTraces.StackFrame}}, Bool, Symbol, Int, UInt}) precompile(Tuple{typeof(Profile.tree!), Profile.StackFrameTree{UInt64}, Vector{UInt64}, Dict{UInt64, Vector{Base.StackTraces.StackFrame}}, Bool, Symbol, Int, UnitRange{UInt}}) precompile(Tuple{typeof(Profile.tree!), Profile.StackFrameTree{UInt64}, Vector{UInt64}, Dict{UInt64, Vector{Base.StackTraces.StackFrame}}, Bool, Symbol, UnitRange{Int}, UInt}) diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index bcb6d30e85201..f8aca313b8c05 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -429,7 +429,7 @@ function get_code_cache() # that those produced by `NativeInterpreter`, will leak into the native code cache, # potentially causing runtime slowdown. # (see https://github.com/JuliaLang/julia/issues/48453). - if (@ccall jl_generating_output()::Cint) == 1 + if Base.generating_output() return REPLInterpreterCache() else return REPL_INTERPRETER_CACHE From 39501675ee4f9d99b7b72c4d4bd084003b87a4c6 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Sat, 9 Sep 2023 07:21:54 -0300 Subject: [PATCH 06/15] Check if malloc has succeeded before updating GC counters (#51247) --- src/gc.c | 68 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/src/gc.c b/src/gc.c index 513b3cceb90b8..bc3526f742ddc 100644 --- a/src/gc.c +++ b/src/gc.c @@ -3650,7 +3650,8 @@ JL_DLLEXPORT void *jl_gc_counted_malloc(size_t sz) { jl_gcframe_t **pgcstack = jl_get_pgcstack(); jl_task_t *ct = jl_current_task; - if (pgcstack != NULL && ct->world_age) { + void *data = malloc(sz); + if (data != NULL && pgcstack != NULL && ct->world_age) { jl_ptls_t ptls = ct->ptls; maybe_collect(ptls); jl_atomic_store_relaxed(&ptls->gc_num.allocd, @@ -3665,14 +3666,15 @@ JL_DLLEXPORT void *jl_gc_counted_malloc(size_t sz) jl_atomic_store_relaxed(&ptls->gc_num.alloc_acc, 0); } } - return malloc(sz); + return data; } JL_DLLEXPORT void *jl_gc_counted_calloc(size_t nm, size_t sz) { jl_gcframe_t **pgcstack = jl_get_pgcstack(); jl_task_t *ct = jl_current_task; - if (pgcstack != NULL && ct->world_age) { + void *data = calloc(nm, sz); + if (data != NULL && pgcstack != NULL && ct->world_age) { jl_ptls_t ptls = ct->ptls; maybe_collect(ptls); jl_atomic_store_relaxed(&ptls->gc_num.allocd, @@ -3687,7 +3689,7 @@ JL_DLLEXPORT void *jl_gc_counted_calloc(size_t nm, size_t sz) jl_atomic_store_relaxed(&ptls->gc_num.alloc_acc, 0); } } - return calloc(nm, sz); + return data; } JL_DLLEXPORT void jl_gc_counted_free_with_size(void *p, size_t sz) @@ -3711,7 +3713,8 @@ JL_DLLEXPORT void *jl_gc_counted_realloc_with_old_size(void *p, size_t old, size { jl_gcframe_t **pgcstack = jl_get_pgcstack(); jl_task_t *ct = jl_current_task; - if (pgcstack != NULL && ct->world_age) { + void *data = realloc(p, sz); + if (data != NULL && pgcstack != NULL && ct->world_age) { jl_ptls_t ptls = ct->ptls; maybe_collect(ptls); if (!(sz < old)) @@ -3741,7 +3744,7 @@ JL_DLLEXPORT void *jl_gc_counted_realloc_with_old_size(void *p, size_t old, size } } } - return realloc(p, sz); + return data; } // allocation wrappers that save the size of allocations, to allow using @@ -3810,6 +3813,15 @@ JL_DLLEXPORT void *jl_gc_managed_malloc(size_t sz) size_t allocsz = LLT_ALIGN(sz, JL_CACHE_BYTE_ALIGNMENT); if (allocsz < sz) // overflow in adding offs, size was "negative" jl_throw(jl_memory_exception); + + int last_errno = errno; +#ifdef _OS_WINDOWS_ + DWORD last_error = GetLastError(); +#endif + void *b = malloc_cache_align(allocsz); + if (b == NULL) + jl_throw(jl_memory_exception); + jl_atomic_store_relaxed(&ptls->gc_num.allocd, jl_atomic_load_relaxed(&ptls->gc_num.allocd) + allocsz); jl_atomic_store_relaxed(&ptls->gc_num.malloc, @@ -3821,13 +3833,6 @@ JL_DLLEXPORT void *jl_gc_managed_malloc(size_t sz) jl_atomic_fetch_add_relaxed(&gc_heap_stats.heap_size, alloc_acc + allocsz); jl_atomic_store_relaxed(&ptls->gc_num.alloc_acc, 0); } - int last_errno = errno; -#ifdef _OS_WINDOWS_ - DWORD last_error = GetLastError(); -#endif - void *b = malloc_cache_align(allocsz); - if (b == NULL) - jl_throw(jl_memory_exception); #ifdef _OS_WINDOWS_ SetLastError(last_error); #endif @@ -3842,12 +3847,28 @@ static void *gc_managed_realloc_(jl_ptls_t ptls, void *d, size_t sz, size_t olds { if (can_collect) maybe_collect(ptls); - + int is_old_marked = jl_astaggedvalue(owner)->bits.gc == GC_OLD_MARKED; size_t allocsz = LLT_ALIGN(sz, JL_CACHE_BYTE_ALIGNMENT); if (allocsz < sz) // overflow in adding offs, size was "negative" jl_throw(jl_memory_exception); - if (jl_astaggedvalue(owner)->bits.gc == GC_OLD_MARKED) { + int last_errno = errno; +#ifdef _OS_WINDOWS_ + DWORD last_error = GetLastError(); +#endif + void *b; + if (isaligned) + b = realloc_cache_align(d, allocsz, oldsz); + else + b = realloc(d, allocsz); + if (b == NULL) + jl_throw(jl_memory_exception); +#ifdef _OS_WINDOWS_ + SetLastError(last_error); +#endif + errno = last_errno; + // gc_managed_realloc_ is currently used exclusively for resizing array buffers. + if (is_old_marked) { ptls->gc_cache.perm_scanned_bytes += allocsz - oldsz; inc_live_bytes(allocsz - oldsz); } @@ -3877,23 +3898,6 @@ static void *gc_managed_realloc_(jl_ptls_t ptls, void *d, size_t sz, size_t olds jl_atomic_store_relaxed(&ptls->gc_num.alloc_acc, 0); } } - - int last_errno = errno; -#ifdef _OS_WINDOWS_ - DWORD last_error = GetLastError(); -#endif - void *b; - if (isaligned) - b = realloc_cache_align(d, allocsz, oldsz); - else - b = realloc(d, allocsz); - if (b == NULL) - jl_throw(jl_memory_exception); -#ifdef _OS_WINDOWS_ - SetLastError(last_error); -#endif - errno = last_errno; - // gc_managed_realloc_ is currently used exclusively for resizing array buffers. if (allocsz > oldsz) { maybe_record_alloc_to_profile((jl_value_t*)b, allocsz - oldsz, (jl_datatype_t*)jl_buff_tag); } From 8d4d641507d860038982e977e14eea1789a78e47 Mon Sep 17 00:00:00 2001 From: Iztok Fister Jr Date: Sat, 9 Sep 2023 15:49:52 +0200 Subject: [PATCH 07/15] Update man page with internet resources and licensing (#51155) Pull request proposes a minor modification to the man page. In this PR, two additional sections for the man page are added: - Internet resources and - licensing. --- doc/man/julia.1 | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/doc/man/julia.1 b/doc/man/julia.1 index 79a0530c2ecd1..95cf73afd0556 100644 --- a/doc/man/julia.1 +++ b/doc/man/julia.1 @@ -21,7 +21,7 @@ .\" - diagnostics .\" - notes -.TH JULIA 1 2022-02-17 JULIA +.TH JULIA 1 2023-09-01 JULIA .\" from the front page of https://julialang.org/ .SH NAME @@ -277,6 +277,15 @@ See https://docs.julialang.org/en/v1/manual/environment-variables/ Please report any bugs using the GitHub issue tracker: https://github.com/julialang/julia/issues?state=open - .SH AUTHORS Contributors: https://github.com/JuliaLang/julia/graphs/contributors + +.SH INTERNET RESOURCES +Website: https://julialang.org/ +.br +Documentation: https://docs.julialang.org/ +.br +Downloads: https://julialang.org/downloads/ + +.SH LICENSING +Julia is an open-source project. It is made available under the MIT license. From bbbcc4fed67337c038b485f00677e2e88d24becd Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Sat, 9 Sep 2023 17:43:01 -0300 Subject: [PATCH 08/15] Add lock around uv_unref during init (#51236) This is not a legal operation outside the lock because it's not atomic Co-authored-by: Valentin Churavy --- base/libuv.jl | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/base/libuv.jl b/base/libuv.jl index 24a04f5bcad78..4c56af29e7e60 100644 --- a/base/libuv.jl +++ b/base/libuv.jl @@ -103,8 +103,17 @@ uv_error(prefix::AbstractString, c::Integer) = c < 0 ? throw(_UVError(prefix, c) eventloop() = ccall(:jl_global_event_loop, Ptr{Cvoid}, ()) -uv_unref(h::Ptr{Cvoid}) = ccall(:uv_unref, Cvoid, (Ptr{Cvoid},), h) -uv_ref(h::Ptr{Cvoid}) = ccall(:uv_ref, Cvoid, (Ptr{Cvoid},), h) +function uv_unref(h::Ptr{Cvoid}) + iolock_begin() + ccall(:uv_unref, Cvoid, (Ptr{Cvoid},), h) + iolock_end() +end + +function uv_ref(h::Ptr{Cvoid}) + iolock_begin() + ccall(:uv_ref, Cvoid, (Ptr{Cvoid},), h) + iolock_end() +end function process_events() return ccall(:jl_process_events, Int32, ()) From 7b9fdf852c1c69085b9ac85faeefe67b093d66c6 Mon Sep 17 00:00:00 2001 From: Valentin Churavy Date: Sat, 9 Sep 2023 21:51:57 -0400 Subject: [PATCH 09/15] Make _global_logstate a typed global (#51257) --- base/logging.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/base/logging.jl b/base/logging.jl index c42af08d8f4ae..04eef9ed2ae51 100644 --- a/base/logging.jl +++ b/base/logging.jl @@ -587,6 +587,8 @@ end end +global _global_logstate::LogState + """ global_logger() From ea49abe85e8a2ff43973124d6c1b10937bbecc12 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Mon, 11 Sep 2023 18:56:41 +0900 Subject: [PATCH 10/15] SROA: remove dead lifting cache mechanism (#51014) It hadn't been fixed for years. Let's get rid of the unnecessary allocation cost. --- base/compiler/ssair/passes.jl | 49 ++++++++++------------------------- 1 file changed, 13 insertions(+), 36 deletions(-) diff --git a/base/compiler/ssair/passes.jl b/base/compiler/ssair/passes.jl index 362aefcde6026..428909e2792ea 100644 --- a/base/compiler/ssair/passes.jl +++ b/base/compiler/ssair/passes.jl @@ -521,8 +521,7 @@ end function lift_comparison! end function lift_comparison!(::typeof(===), compact::IncrementalCompact, - idx::Int, stmt::Expr, lifting_cache::IdDict{Pair{AnySSAValue, Any}, AnySSAValue}, - 𝕃ₒ::AbstractLattice) + idx::Int, stmt::Expr, 𝕃ₒ::AbstractLattice) args = stmt.args length(args) == 3 || return lhs, rhs = args[2], args[3] @@ -538,28 +537,26 @@ function lift_comparison!(::typeof(===), compact::IncrementalCompact, else return end - lift_comparison_leaves!(egal_tfunc, compact, val, cmp, lifting_cache, idx, 𝕃ₒ) + lift_comparison_leaves!(egal_tfunc, compact, val, cmp, idx, 𝕃ₒ) end function lift_comparison!(::typeof(isa), compact::IncrementalCompact, - idx::Int, stmt::Expr, lifting_cache::IdDict{Pair{AnySSAValue, Any}, AnySSAValue}, - 𝕃ₒ::AbstractLattice) + idx::Int, stmt::Expr, 𝕃ₒ::AbstractLattice) args = stmt.args length(args) == 3 || return cmp = argextype(args[3], compact) val = args[2] - lift_comparison_leaves!(isa_tfunc, compact, val, cmp, lifting_cache, idx, 𝕃ₒ) + lift_comparison_leaves!(isa_tfunc, compact, val, cmp, idx, 𝕃ₒ) end function lift_comparison!(::typeof(isdefined), compact::IncrementalCompact, - idx::Int, stmt::Expr, lifting_cache::IdDict{Pair{AnySSAValue, Any}, AnySSAValue}, - 𝕃ₒ::AbstractLattice) + idx::Int, stmt::Expr, 𝕃ₒ::AbstractLattice) args = stmt.args length(args) == 3 || return cmp = argextype(args[3], compact) isa(cmp, Const) || return # `isdefined_tfunc` won't return Const val = args[2] - lift_comparison_leaves!(isdefined_tfunc, compact, val, cmp, lifting_cache, idx, 𝕃ₒ) + lift_comparison_leaves!(isdefined_tfunc, compact, val, cmp, idx, 𝕃ₒ) end function phi_or_ifelse_predecessors(@nospecialize(def), compact::IncrementalCompact) @@ -570,15 +567,13 @@ end function lift_comparison_leaves!(@specialize(tfunc), compact::IncrementalCompact, @nospecialize(val), @nospecialize(cmp), - lifting_cache::IdDict{Pair{AnySSAValue, Any}, AnySSAValue}, idx::Int, - 𝕃ₒ::AbstractLattice) + idx::Int, 𝕃ₒ::AbstractLattice) typeconstraint = widenconst(argextype(val, compact)) if isa(val, Union{OldSSAValue, SSAValue}) val, typeconstraint = simple_walk_constraint(compact, val, typeconstraint) end isa(typeconstraint, Union) || return # bail out if there won't be a good chance for lifting - leaves, visited_philikes = collect_leaves(compact, val, typeconstraint, 𝕃ₒ, phi_or_ifelse_predecessors) length(leaves) ≤ 1 && return # bail out if we don't have multiple leaves @@ -599,8 +594,7 @@ function lift_comparison_leaves!(@specialize(tfunc), # perform lifting lifted_val = perform_lifting!(compact, - visited_philikes, cmp, lifting_cache, Bool, - lifted_leaves::LiftedLeaves, val, nothing)::LiftedValue + visited_philikes, cmp, Bool, lifted_leaves::LiftedLeaves, val, nothing)::LiftedValue compact[idx] = lifted_val.val end @@ -655,7 +649,6 @@ end function perform_lifting!(compact::IncrementalCompact, visited_philikes::Vector{AnySSAValue}, @nospecialize(cache_key), - lifting_cache::IdDict{Pair{AnySSAValue, Any}, AnySSAValue}, @nospecialize(result_t), lifted_leaves::Union{LiftedLeaves, LiftedDefs}, @nospecialize(stmt_val), lazydomtree::Union{LazyDomtree,Nothing}) reverse_mapping = IdDict{AnySSAValue, Int}() @@ -704,19 +697,6 @@ function perform_lifting!(compact::IncrementalCompact, old_ssa = visited_philikes[i] old_inst = compact[old_ssa] old_node = old_inst[:stmt]::Union{PhiNode,Expr} - # FIXME this cache is broken somehow - # ckey = Pair{AnySSAValue, Any}(old_ssa, cache_key) - # cached = ckey in keys(lifting_cache) - cached = false - if cached - ssa = lifting_cache[ckey] - if isa(old_node, PhiNode) - lifted_philikes[i] = LiftedPhilike(ssa, old_node, false) - else - lifted_philikes[i] = LiftedPhilike(ssa, IfElseCall(old_node), false) - end - continue - end if isa(old_node, PhiNode) new_node = PhiNode() ssa = insert_node!(compact, old_ssa, effect_free_and_nothrow(NewInstruction(new_node, result_t))) @@ -734,7 +714,6 @@ function perform_lifting!(compact::IncrementalCompact, ssa = insert_node!(compact, old_ssa, new_inst, #= attach_after =# true) lifted_philikes[i] = LiftedPhilike(ssa, IfElseCall(new_node), true) end - # lifting_cache[ckey] = ssa end # Fix up arguments @@ -1018,8 +997,6 @@ function sroa_pass!(ir::IRCode, inlining::Union{Nothing,InliningState}=nothing) 𝕃ₒ = inlining === nothing ? SimpleInferenceLattice.instance : optimizer_lattice(inlining.interp) compact = IncrementalCompact(ir) defuses = nothing # will be initialized once we encounter mutability in order to reduce dynamic allocations - lifting_cache = IdDict{Pair{AnySSAValue, Any}, AnySSAValue}() - def_lifting_cache = IdDict{Pair{AnySSAValue, Any}, AnySSAValue}() # initialization of domtree is delayed to avoid the expensive computation in many cases lazydomtree = LazyDomtree(ir) for ((_, idx), stmt) in compact @@ -1110,9 +1087,9 @@ function sroa_pass!(ir::IRCode, inlining::Union{Nothing,InliningState}=nothing) elseif is_known_call(stmt, Core._svec_ref, compact) lift_svec_ref!(compact, idx, stmt) elseif is_known_call(stmt, (===), compact) - lift_comparison!(===, compact, idx, stmt, lifting_cache, 𝕃ₒ) + lift_comparison!(===, compact, idx, stmt, 𝕃ₒ) elseif is_known_call(stmt, isa, compact) - lift_comparison!(isa, compact, idx, stmt, lifting_cache, 𝕃ₒ) + lift_comparison!(isa, compact, idx, stmt, 𝕃ₒ) elseif is_known_call(stmt, Core.ifelse, compact) fold_ifelse!(compact, idx, stmt) elseif isexpr(stmt, :new) @@ -1131,7 +1108,7 @@ function sroa_pass!(ir::IRCode, inlining::Union{Nothing,InliningState}=nothing) struct_argtyp = argument_datatype(struct_typ) if struct_argtyp === nothing if isa(struct_typ, Union) && is_isdefined - lift_comparison!(isdefined, compact, idx, stmt, lifting_cache, 𝕃ₒ) + lift_comparison!(isdefined, compact, idx, stmt, 𝕃ₒ) end continue end @@ -1191,7 +1168,7 @@ function sroa_pass!(ir::IRCode, inlining::Union{Nothing,InliningState}=nothing) end lifted_val = perform_lifting!(compact, - visited_philikes, field, lifting_cache, result_t, lifted_leaves, val, lazydomtree) + visited_philikes, field, result_t, lifted_leaves, val, lazydomtree) # Insert the undef check if necessary if any_undef @@ -1203,7 +1180,7 @@ function sroa_pass!(ir::IRCode, inlining::Union{Nothing,InliningState}=nothing) lifted_leaves_def[k] = v === nothing ? false : true end def_val = perform_lifting!(compact, - visited_philikes, field, def_lifting_cache, Bool, lifted_leaves_def, val, lazydomtree).val + visited_philikes, field, Bool, lifted_leaves_def, val, lazydomtree).val end insert_node!(compact, SSAValue(idx), NewInstruction( Expr(:throw_undef_if_not, Symbol("##getfield##"), def_val), Nothing)) From 10974814b3faa1dea140062cfe1f3e63962074d5 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Mon, 11 Sep 2023 16:39:29 +0200 Subject: [PATCH 11/15] GMP: Gracefully handle more overflows. (#51243) Fixes https://github.com/JuliaLang/julia/issues/8286, which regressed due to a GMP upgrade in https://github.com/JuliaLang/julia/pull/45375. --- deps/checksums/gmp | 116 ++++++++++----------- deps/gmp.mk | 7 +- deps/patches/gmp-more_alloc_overflow.patch | 37 +++++++ stdlib/GMP_jll/Project.toml | 2 +- test/gmp.jl | 5 + 5 files changed, 107 insertions(+), 60 deletions(-) create mode 100644 deps/patches/gmp-more_alloc_overflow.patch diff --git a/deps/checksums/gmp b/deps/checksums/gmp index 312f79dfc1d6a..c9f6deac6e19b 100644 --- a/deps/checksums/gmp +++ b/deps/checksums/gmp @@ -1,60 +1,60 @@ -GMP.v6.2.1+5.aarch64-apple-darwin.tar.gz/md5/56a01b4c21e4bc3ef3014f162c78e0a7 -GMP.v6.2.1+5.aarch64-apple-darwin.tar.gz/sha512/4c0e31f03965602b811be25847b94e227c63f66a152225477468303a44dd0f148970aaaf00e9cf800ba7df602b31b75f64c28e509362bf82b9c9f341b044a20d -GMP.v6.2.1+5.aarch64-linux-gnu-cxx03.tar.gz/md5/a1beafc662eaf934dfb3cec74ea8fe6b -GMP.v6.2.1+5.aarch64-linux-gnu-cxx03.tar.gz/sha512/370de52ddaa4e744bb6cc8eb61bc369e4e96dccdff6b1a65f21d30d4a19d0dbe41c068c8867c0fcd2bffee9aaf375c60050263dcf7c10b215b290253a7654c71 -GMP.v6.2.1+5.aarch64-linux-gnu-cxx11.tar.gz/md5/afaca916697bcdac17f4dba7444cd467 -GMP.v6.2.1+5.aarch64-linux-gnu-cxx11.tar.gz/sha512/cd7bf7c502e927a05ecde303733240c0245b239447ed4c8c3d13a52b42e47cde48264726321ff318ad6f8c08e8cf4e0c85ac875dade355720fbd7e8b33392092 -GMP.v6.2.1+5.aarch64-linux-musl-cxx03.tar.gz/md5/1d7b2be36a999f2b991abae4b9a350c9 -GMP.v6.2.1+5.aarch64-linux-musl-cxx03.tar.gz/sha512/6e4f04980a2d326a2ec2ba9b52cb4143fc227459c936706cac9f19c67607019927dc8d9f4822a73c885eb3ab2c37c6af806bff50e1e76d546274979d2589e140 -GMP.v6.2.1+5.aarch64-linux-musl-cxx11.tar.gz/md5/d114c9a351854c62b4f4724302a61677 -GMP.v6.2.1+5.aarch64-linux-musl-cxx11.tar.gz/sha512/1a0d4e3ef9fd4e2bf17cf0d90b262c1cd4f684e1ed31b6e040afe59cc13ec3dc3ce274f55c62c19217bffdd847850fe55a607f616422e2c31d92d7553100ee98 -GMP.v6.2.1+5.armv6l-linux-gnueabihf-cxx03.tar.gz/md5/3e5989fb44bc6e2cb4054e885e931cc6 -GMP.v6.2.1+5.armv6l-linux-gnueabihf-cxx03.tar.gz/sha512/b42884d9a8d9a7a63f51f602c3cc1c2b80a6fd4aaaa47eebcf89a42443b25ba9691da844d2ac69a46b4099a5bdb34c8089f4efd8ca213d6d9866c2076d1fe061 -GMP.v6.2.1+5.armv6l-linux-gnueabihf-cxx11.tar.gz/md5/c65ae9faa092285cc4082bfd585e7b03 -GMP.v6.2.1+5.armv6l-linux-gnueabihf-cxx11.tar.gz/sha512/74ab5afd05de93315d3e2b7f2ee6b86a2dbc165621e98cbc08b9c61146d595189b641f2bb8af4cd17d868325fa2a193b9f350e0ed457ca8bc9b96bdfb72c51e6 -GMP.v6.2.1+5.armv6l-linux-musleabihf-cxx03.tar.gz/md5/cc8e27fc3ec1c1f9e044c9d918d8cfb6 -GMP.v6.2.1+5.armv6l-linux-musleabihf-cxx03.tar.gz/sha512/59ae96ed0571ce64a44798767c389f4822222d9519422b5050d22ada68d57371583d4de82c6d22d9636aa2e25cfd9528151364fbf207fdb391bc61d4ad3265e1 -GMP.v6.2.1+5.armv6l-linux-musleabihf-cxx11.tar.gz/md5/e5eb9e0084bf9b4b28c7d1060893159f -GMP.v6.2.1+5.armv6l-linux-musleabihf-cxx11.tar.gz/sha512/3befcb4638d29e4d05ba1bc438e5f861a69385f5a3aa2a331194bed8f7f69331ebc61577dadec97a7c2c42e53a6dd240e30c19d4854af0670b98b02f11afc35d -GMP.v6.2.1+5.armv7l-linux-gnueabihf-cxx03.tar.gz/md5/a3feda2d30469e8980f7c1d1694f2a65 -GMP.v6.2.1+5.armv7l-linux-gnueabihf-cxx03.tar.gz/sha512/d6787b7beca9c98e1e8771842052e5f332dc4d34a1d53968704cc54056477072a7cf0c87ae4c9a51ea35c4b4de14cad6f67579469bb802e50eb6d49d65bd0540 -GMP.v6.2.1+5.armv7l-linux-gnueabihf-cxx11.tar.gz/md5/989a83feae172a0f01670d89065ac58c -GMP.v6.2.1+5.armv7l-linux-gnueabihf-cxx11.tar.gz/sha512/331a08346f8fd7d70a3cd40b1f9c6e7790751cadc9f3027bb1a815314c2e54bae5268a2ecca53a1a5086366641ef7389cb9574cd5f0431dee70ddedff7870b6c -GMP.v6.2.1+5.armv7l-linux-musleabihf-cxx03.tar.gz/md5/705e406788adacc5d73746306215e412 -GMP.v6.2.1+5.armv7l-linux-musleabihf-cxx03.tar.gz/sha512/32fa29cb8abcb823cc1e170c4e1ea09b1f970207279c88ac78df352bb3969590e50fc9eb6446d9c5044f5fae2168878614b189cb1cc612ae8b8afe820b83778a -GMP.v6.2.1+5.armv7l-linux-musleabihf-cxx11.tar.gz/md5/2fff6e51075ce3b64c7684451d3a057c -GMP.v6.2.1+5.armv7l-linux-musleabihf-cxx11.tar.gz/sha512/266036a380e3e58e799f1f03129321345a0c4d9db60b88d12166c7c6d817279239aa2e2cbf2442435e12bba8cef18c48fe9844d0b88f0026be67378e18f135c2 -GMP.v6.2.1+5.i686-linux-gnu-cxx03.tar.gz/md5/7f07924e4a691436727621e2fd1ff349 -GMP.v6.2.1+5.i686-linux-gnu-cxx03.tar.gz/sha512/3e33534fd8ba681c9e4dddd0dbb1c287b1fcb284a55ae13ac685b73d79036fb9de39443e4fbba9f7d3e804ad85c6128ce2e138f92e19df17cda51297089be300 -GMP.v6.2.1+5.i686-linux-gnu-cxx11.tar.gz/md5/5882ef18722ca8ea83fc64796ac9a6fc -GMP.v6.2.1+5.i686-linux-gnu-cxx11.tar.gz/sha512/45a25dc59060640accbb9d09574f769da05c448891a7e00b608ec3349c3d05b41710c49cd7d7fa4c5101adc9db1625ff19082715d1a9296e9da957520cca8e9e -GMP.v6.2.1+5.i686-linux-musl-cxx03.tar.gz/md5/dbf0e6f7b74e48ff63e136b4703a92df -GMP.v6.2.1+5.i686-linux-musl-cxx03.tar.gz/sha512/69321bd73da7271147f6cb073c9c8e853ab5b6b84d2cf196df197121a6fe0f6c1c64839bfd1106bba7e547b02f9dd32be9603d76be270e1e22854c600141e80f -GMP.v6.2.1+5.i686-linux-musl-cxx11.tar.gz/md5/94204c12eba64544f58a3dc0b8afc43e -GMP.v6.2.1+5.i686-linux-musl-cxx11.tar.gz/sha512/734b529a24b85eca85b3a95a3df9673a5aa51e2c61456557d273c122870018b574b09a678263c122bcef706c47dc69b142aeb688ccdcd39761eb8ca45e635a3f -GMP.v6.2.1+5.i686-w64-mingw32-cxx03.tar.gz/md5/327155a11581b319a58e780eb97628ad -GMP.v6.2.1+5.i686-w64-mingw32-cxx03.tar.gz/sha512/32c6eaaa3e2d6cc354d7c8cd8cd3b348d560d818f8af0fe8d738b8476e811d38c0d85d4dad9433ce9915322ce2c7634480340c0aace987eebeffd692f4a325d0 -GMP.v6.2.1+5.i686-w64-mingw32-cxx11.tar.gz/md5/d7ae966f2ffef8abfb731579c4ef5fb0 -GMP.v6.2.1+5.i686-w64-mingw32-cxx11.tar.gz/sha512/ebf234e3dd983d49f68ea2322d2658f9cad53de4ec94a0db33f47860331991ca765ec86a646242fdbbeb36051a182767de75ad47e7808bcbac32b196cbc538b3 -GMP.v6.2.1+5.powerpc64le-linux-gnu-cxx03.tar.gz/md5/96bab6f8a36d110065cbe06d8fa654ef -GMP.v6.2.1+5.powerpc64le-linux-gnu-cxx03.tar.gz/sha512/d5472ea1a16ec2312e96b85cba9209eb543abca1b07c48fd7a31c42892fe4a9a2368edbb2f2410580a9ff3337a6b9dbb6cad377fc2ffa66746d4a25fb2da4d46 -GMP.v6.2.1+5.powerpc64le-linux-gnu-cxx11.tar.gz/md5/41704d02be36f94086f8e79124c15410 -GMP.v6.2.1+5.powerpc64le-linux-gnu-cxx11.tar.gz/sha512/dc1800a7e796b4e5dea7c7136545a3120b619f25e28b3aa7e2478dc27d4224160bfc0e03875c4fdd6703c854a8851b27b0f23fd2f5470450230bfb33e337a420 -GMP.v6.2.1+5.x86_64-apple-darwin.tar.gz/md5/ec93617dd921d13eeccf946aeda3bdab -GMP.v6.2.1+5.x86_64-apple-darwin.tar.gz/sha512/a1c490e969d2d747d81016381bbabd6c07915ceca456e4fa77f0bb473193fa013dc185ae4b8bb8bd3451a25d9779f90039ac362d8c911fc307928af22e79a50c -GMP.v6.2.1+5.x86_64-linux-gnu-cxx03.tar.gz/md5/899dadfaaf4cd1d787ac6a905c108a02 -GMP.v6.2.1+5.x86_64-linux-gnu-cxx03.tar.gz/sha512/d304e85f17503a8e9472b69e908f04c6c3e8e3a88f3692f86c0e1e8d5576620b9b144e2224111a7e6f0eb5a58c6f1cb536803764fc8be13a8ef3147f3bbf779a -GMP.v6.2.1+5.x86_64-linux-gnu-cxx11.tar.gz/md5/ece1ecee696e47609ab06b6463f3ede2 -GMP.v6.2.1+5.x86_64-linux-gnu-cxx11.tar.gz/sha512/7fee1caf74f01d2ac9538642901f969f1715ce84199dccd17e016fdeab22fa5dc7a6865e1b5ebf7f54b287d51f7eb48eba4a0b7eb80b8fc4485e49198b914531 -GMP.v6.2.1+5.x86_64-linux-musl-cxx03.tar.gz/md5/aff0fb74a84d0867f2692bf61787bfd1 -GMP.v6.2.1+5.x86_64-linux-musl-cxx03.tar.gz/sha512/057d552a433f0f4e8d1f5cc1c3f1125f5096a7de72ce41ecb1ab2b7e378e0e39f323a4c50f8875c8ba1a5b66541b83e0841fe60f0ece168aeb3a9b63d3eac68f -GMP.v6.2.1+5.x86_64-linux-musl-cxx11.tar.gz/md5/89f6a22a065acbb2366076b271949141 -GMP.v6.2.1+5.x86_64-linux-musl-cxx11.tar.gz/sha512/93cdb3b1ccfbc7c0aca1f9497022d2ea69a023142d59144853300f02b5a25a8f6eacb5da68ff6dc6e969bc315d14386c75aedb828670e96fe84ccb83591bbde4 -GMP.v6.2.1+5.x86_64-unknown-freebsd.tar.gz/md5/285707b8dedcee127959bde79d6ad622 -GMP.v6.2.1+5.x86_64-unknown-freebsd.tar.gz/sha512/77d70f2b29d0bc1fd6c2d938db5b1883697b181d05491931c53eb6d23d84560743fb069ed3b8b9374fdf7d3c37b1f8f732d038e133e38fd3f42a8182ef50fc20 -GMP.v6.2.1+5.x86_64-w64-mingw32-cxx03.tar.gz/md5/fe8257f44266f6741eca3ff288048725 -GMP.v6.2.1+5.x86_64-w64-mingw32-cxx03.tar.gz/sha512/225bf51c55de35cf81e36d848e2fae2646722ceea2e72d66d6d476422df2f5960819db4f3d8a89428fe4d865a657ee4313398109f6fe688971d151cbcd69a279 -GMP.v6.2.1+5.x86_64-w64-mingw32-cxx11.tar.gz/md5/cfb3c9a7a015a271f50dd2a55b55297e -GMP.v6.2.1+5.x86_64-w64-mingw32-cxx11.tar.gz/sha512/a8b6587d9e6a8964d1ff914402b48a6f8ad52cbca96ba5bf732e4e232bf0c942d535926e755983c5e4cc4aa90b473edeac44742ef498963d1276f1ff3c49fa98 +GMP.v6.2.1+6.aarch64-apple-darwin.tar.gz/md5/8123f7925ae9aa60b6998313b21a9db9 +GMP.v6.2.1+6.aarch64-apple-darwin.tar.gz/sha512/5c7927ecfd47409dd4116cd4209768294ba229b51472ed220da498823dc1e7f9100292ec4b3a990491acd27f16ce3a3dce7a7c6e20dcd515982a9c8e364d91bc +GMP.v6.2.1+6.aarch64-linux-gnu-cxx03.tar.gz/md5/0d0d2ee67cff251941e3474341280b34 +GMP.v6.2.1+6.aarch64-linux-gnu-cxx03.tar.gz/sha512/69fb2f1476e0bb73f89ad2f73b58ec4da1b99e099124666e6da93b7705fde23913daa59f2ad479f99fcb4f0df152603bb0ba4875420b583f01fded0fec280a15 +GMP.v6.2.1+6.aarch64-linux-gnu-cxx11.tar.gz/md5/86ba1313c8ab4ca1ae8313cbf96e1e7d +GMP.v6.2.1+6.aarch64-linux-gnu-cxx11.tar.gz/sha512/05c306c01d1b0e9e4dc7ce937075eeaede4e5e0791826a8892fae2eb73cdb7f22c4873cf31cea3cfe3db996ac77387346f4f8a851ce52c29883146678f3851fd +GMP.v6.2.1+6.aarch64-linux-musl-cxx03.tar.gz/md5/2fbbb9adee7db794f5888442b7b7688c +GMP.v6.2.1+6.aarch64-linux-musl-cxx03.tar.gz/sha512/d8a1719e529374d00ba6372013d0c7ddc9f44f9f6ee0f966b4ed16d731ce74c26b6e6a807403b3396bed67dd3e775e18c1e70c247a371d622a6e7013eb6b8905 +GMP.v6.2.1+6.aarch64-linux-musl-cxx11.tar.gz/md5/b6a8c494d4c90decb6eacbca3ce3f22a +GMP.v6.2.1+6.aarch64-linux-musl-cxx11.tar.gz/sha512/6798406e20cc4d58647c266a2b1b8d0670e62f19bf4bff991c39eef13cf92c043f00717e7289bcc00007d7e248e943b37ba2eef89c9e68c42e30f0e2be9dd589 +GMP.v6.2.1+6.armv6l-linux-gnueabihf-cxx03.tar.gz/md5/a6866ee9784e9359e32dc18f417b2be7 +GMP.v6.2.1+6.armv6l-linux-gnueabihf-cxx03.tar.gz/sha512/548953ccc8444886316d4dfd7081783e397ec180e88a1d17a464e4b1d0a27f51ee7f6a1936ddab499db192d3cdfdc87d572731c5ab2f87d528609dabfccad2d3 +GMP.v6.2.1+6.armv6l-linux-gnueabihf-cxx11.tar.gz/md5/6b78c826a4aedc8107c1bbfccbe5c097 +GMP.v6.2.1+6.armv6l-linux-gnueabihf-cxx11.tar.gz/sha512/e8c075c29e4d8a916f087faeb2db50168e1a5546fcb02fc841477cf82a39188c3b9e7703b5354d4842880b5ac7215a32d022abe08aacc5e23238b63c6b994af4 +GMP.v6.2.1+6.armv6l-linux-musleabihf-cxx03.tar.gz/md5/57e1a6c71b3c5b4047bf08bfc4d4f22d +GMP.v6.2.1+6.armv6l-linux-musleabihf-cxx03.tar.gz/sha512/0f72c675ab3005ea183393bc4e5b4a157c13042367fd1bb3b03b3f7742e09604bddffb89f1478dc0dab4d992939519578549d05f9885b89319b0b51678b8a619 +GMP.v6.2.1+6.armv6l-linux-musleabihf-cxx11.tar.gz/md5/65a13f49cbdaa9d3a8e20d0b84bbc701 +GMP.v6.2.1+6.armv6l-linux-musleabihf-cxx11.tar.gz/sha512/0487b18d1c9c59d990e6c4ec435b8dff91ae02d5d56c665b12aaaea105f7d2ab5beae9dfcbb133c990f70774b0d32e55df7f2e91e2d0a85c391a4090dcadf080 +GMP.v6.2.1+6.armv7l-linux-gnueabihf-cxx03.tar.gz/md5/30e20c183153f8ce60e564b35e4b54bd +GMP.v6.2.1+6.armv7l-linux-gnueabihf-cxx03.tar.gz/sha512/41bdabc2610b46b215043e98eaddb2e2ad0695ae15f3088c9beef24a97864dce4088ae68993de928d952baaf123f279d74705664fffbf96be9b7436f1ba7692b +GMP.v6.2.1+6.armv7l-linux-gnueabihf-cxx11.tar.gz/md5/5f2cba31677e6681666c0b6ebd33c3ad +GMP.v6.2.1+6.armv7l-linux-gnueabihf-cxx11.tar.gz/sha512/a89399bf84bebf4b8432e48aae6dce5547bb6f1c048364697c577541c4f1a555b976370634624e9cf039fcbcb70e449a2f55563f0a4f48e60ee4653a185cf7dd +GMP.v6.2.1+6.armv7l-linux-musleabihf-cxx03.tar.gz/md5/4a682d832109d7ab5743832f73ca33d2 +GMP.v6.2.1+6.armv7l-linux-musleabihf-cxx03.tar.gz/sha512/d5062bd8eee926eb1177e70e5d9e8d6ed7a00a17c25d2b165b974c01aa79d45ca97e219b26ded752b5f323546192d595b838b474c61bdd87e641549db9e9ef5d +GMP.v6.2.1+6.armv7l-linux-musleabihf-cxx11.tar.gz/md5/caa51529cb1b6dc8db765e202e1b7737 +GMP.v6.2.1+6.armv7l-linux-musleabihf-cxx11.tar.gz/sha512/d11ae870e68ca8d28bbcdf799a04769c3df2fbd169f6f2b16d88a556c40866b39636820ac3497e869086e638ba31dc1c87ec780add2d1aafe5e4ca178641678e +GMP.v6.2.1+6.i686-linux-gnu-cxx03.tar.gz/md5/dfcb024b9cfba37f80da5b7cc0c5b1ad +GMP.v6.2.1+6.i686-linux-gnu-cxx03.tar.gz/sha512/10eb086228b4250ecce11ad5bbec15e2bfff2429530cfd700602ead7f108163bc48fc83d9714443cbf5a93e7dd5f9046bdc15ef324486475f6b4be1cf34bad4b +GMP.v6.2.1+6.i686-linux-gnu-cxx11.tar.gz/md5/e889c1d65c9ca710c859129ae99ef322 +GMP.v6.2.1+6.i686-linux-gnu-cxx11.tar.gz/sha512/4d97ebdd6a12d39907ccc9bad00266e286c949b3f99a306c1c4a4380a292694d944f275c351d9ddf465d020c8197b3b19dfccb5080249c75e3f5ffb9aa77a1c4 +GMP.v6.2.1+6.i686-linux-musl-cxx03.tar.gz/md5/d57b3948e7a120bafeae67c28fe40869 +GMP.v6.2.1+6.i686-linux-musl-cxx03.tar.gz/sha512/88165c809a73007d2b5e750d23c619fbb088f6de200aae1dee34b5e3783949150d91b94774cd1881d2a621d092c0e7e7332707ed4737ff8426686dfce7e0313a +GMP.v6.2.1+6.i686-linux-musl-cxx11.tar.gz/md5/e3c53fc468a9f48f9d06fdf51eafae62 +GMP.v6.2.1+6.i686-linux-musl-cxx11.tar.gz/sha512/3c6a99acd84c226d7a48177c8e18624a677ea2a3df15fb2d54002eb5a6d55144b6f51f82ff491373366f32e92252fd14747503166621c2d2359029bdb1b20741 +GMP.v6.2.1+6.i686-w64-mingw32-cxx03.tar.gz/md5/64b9bed188f9a300200659efdb9facef +GMP.v6.2.1+6.i686-w64-mingw32-cxx03.tar.gz/sha512/f7ed47cc29be31f99e612abd1db0d806ece84c117677cd639e04e2f6b08bbbfa4056ed9504bb073ec5f722de6955db668934f3d3ca05ddde0f22b096afcea2e3 +GMP.v6.2.1+6.i686-w64-mingw32-cxx11.tar.gz/md5/a8f38cefb46dc9c3faddfd597d0e1a4c +GMP.v6.2.1+6.i686-w64-mingw32-cxx11.tar.gz/sha512/f02c3458c05869fab493d9be5ea98390baf6eed136fe2916cd6214c4f24a6f22d0716d59f352454fd4c799df71a8fd90e3a169644e1c6ffe89f3620f2a52f158 +GMP.v6.2.1+6.powerpc64le-linux-gnu-cxx03.tar.gz/md5/7f8da2b7e16ef4cb593fea4bdb2e43eb +GMP.v6.2.1+6.powerpc64le-linux-gnu-cxx03.tar.gz/sha512/d0105fe7dfcc1daf7024d2f58b53240bab473c3ae44a904833d009beeb8e41f5487430f68e79bd79fc5c74b55f1111eb7479fedc84bcb45fe4dff3d8c3ac3e4f +GMP.v6.2.1+6.powerpc64le-linux-gnu-cxx11.tar.gz/md5/31fb7b6e37c650f0b8c3a2d475cb2b5b +GMP.v6.2.1+6.powerpc64le-linux-gnu-cxx11.tar.gz/sha512/d03f3f1303996008ff267682de5b9d6e3be78ca1b0d6aa7cadbf4a612b331fe70460b689125f4ededa1c6078092ad3dafaad32c68a98d31713764a7a7461cf98 +GMP.v6.2.1+6.x86_64-apple-darwin.tar.gz/md5/9276d90b4f850f167f673f731c7d3781 +GMP.v6.2.1+6.x86_64-apple-darwin.tar.gz/sha512/f914452a49988b0694915483547c2f878c0ba71be2079fd1228b3e583cb08e92d8c958a052f29025054ded74cacb699893a5a6ef27749c851e83607ad3f1fe8f +GMP.v6.2.1+6.x86_64-linux-gnu-cxx03.tar.gz/md5/cded149fcef93ab1ba89c51d7cc58b73 +GMP.v6.2.1+6.x86_64-linux-gnu-cxx03.tar.gz/sha512/8f97582d6323df6f86e3079b9a2534425bd4e64bb4cec337c21059605d50c1220fd006e55bdb34e8aa7195cd79ef518f1541c1b1a92187ed928f7939b3128dd6 +GMP.v6.2.1+6.x86_64-linux-gnu-cxx11.tar.gz/md5/0529bb60dcf584222cd91e9e11510f24 +GMP.v6.2.1+6.x86_64-linux-gnu-cxx11.tar.gz/sha512/0532821e81a4e51363570f87ec59c37dea24cab59a94e43127837ce4b388d1951853d50e52d4c9f30b4a21cfe222e368207239ce8ac0f1ee1e9375f51fb10127 +GMP.v6.2.1+6.x86_64-linux-musl-cxx03.tar.gz/md5/2d332d096da5515581ee92128aff88ab +GMP.v6.2.1+6.x86_64-linux-musl-cxx03.tar.gz/sha512/b17f7b762bd4d61fa4c4be8124275c2b337383da167bdeaca34e44d71f20716b182b46bc5a6714a798a0951d73b335ab9c87f451cf4c5456edbe76cf3ad36ba4 +GMP.v6.2.1+6.x86_64-linux-musl-cxx11.tar.gz/md5/a9dae953f9d59589162a3ea149c46d1e +GMP.v6.2.1+6.x86_64-linux-musl-cxx11.tar.gz/sha512/31e568aba38a29ec6713dda9eb1c7d7b50c2a736e8883ae8ff2eaf16840b15c93e6dc53025e7750d3ac3e4ffc7d2c91787bda5b799ecfdeea3d928657176b1b3 +GMP.v6.2.1+6.x86_64-unknown-freebsd.tar.gz/md5/6f42d7486fa85ce1bf0cac409d1dd5ae +GMP.v6.2.1+6.x86_64-unknown-freebsd.tar.gz/sha512/5111751619388e51d1b3c0e32548a6de0aa02b7967994a4b4b78cdc9e0e852dae9d78bf48a503a6fb67e3b08343ddcf5a9f0b7a64a803c4d5067d69e4cb2edee +GMP.v6.2.1+6.x86_64-w64-mingw32-cxx03.tar.gz/md5/39cca70db2d23bc73a47870a0ee5156c +GMP.v6.2.1+6.x86_64-w64-mingw32-cxx03.tar.gz/sha512/a2877a6641e4cccd39e7ef093dd9ba7501c6e312f160b2924880d129195aadb74badfbf198fd6ee11035a6a7c99d64c0965c44526104a43569ca0d97fa565b5a +GMP.v6.2.1+6.x86_64-w64-mingw32-cxx11.tar.gz/md5/e2e03ed150558405ca1993ca14488662 +GMP.v6.2.1+6.x86_64-w64-mingw32-cxx11.tar.gz/sha512/50995f6382ed2a4c425097e7abf762b847872734c104847f6a042090be132c68e864d34bb24baf64832d3636810cb631464767949eb2df2fedaa7ccd9824f78b gmp-6.2.1.tar.bz2/md5/28971fc21cf028042d4897f02fd355ea gmp-6.2.1.tar.bz2/sha512/8904334a3bcc5c896ececabc75cda9dec642e401fb5397c4992c4fabea5e962c9ce8bd44e8e4233c34e55c8010cc28db0545f5f750cbdbb5f00af538dc763be9 diff --git a/deps/gmp.mk b/deps/gmp.mk index 12ba15f8aa0f6..0ebabe53acf8d 100644 --- a/deps/gmp.mk +++ b/deps/gmp.mk @@ -57,7 +57,12 @@ $(SRCCACHE)/gmp-$(GMP_VER)/gmp-CVE-2021-43618.patch-applied: $(SRCCACHE)/gmp-$(G patch -p1 < $(SRCDIR)/patches/gmp-CVE-2021-43618.patch echo 1 > $@ -$(SRCCACHE)/gmp-$(GMP_VER)/source-patched: $(SRCCACHE)/gmp-$(GMP_VER)/gmp-CVE-2021-43618.patch-applied +$(SRCCACHE)/gmp-$(GMP_VER)/gmp-more_alloc_overflow.patch-applied: $(SRCCACHE)/gmp-$(GMP_VER)/gmp-CVE-2021-43618.patch-applied + cd $(dir $@) && \ + patch -p1 < $(SRCDIR)/patches/gmp-more_alloc_overflow.patch + echo 1 > $@ + +$(SRCCACHE)/gmp-$(GMP_VER)/source-patched: $(SRCCACHE)/gmp-$(GMP_VER)/gmp-more_alloc_overflow.patch-applied echo 1 > $@ $(BUILDDIR)/gmp-$(GMP_VER)/build-configured: $(SRCCACHE)/gmp-$(GMP_VER)/source-patched diff --git a/deps/patches/gmp-more_alloc_overflow.patch b/deps/patches/gmp-more_alloc_overflow.patch new file mode 100644 index 0000000000000..09d07d7dbd8d5 --- /dev/null +++ b/deps/patches/gmp-more_alloc_overflow.patch @@ -0,0 +1,37 @@ +diff -ur gmp-6.2.1.orig/mpz/n_pow_ui.c gmp-6.2.1/mpz/n_pow_ui.c +--- gmp-6.2.1.orig/mpz/n_pow_ui.c 2023-09-08 11:41:16.620551175 +0200 ++++ gmp-6.2.1/mpz/n_pow_ui.c 2023-09-08 12:49:29.650492180 +0200 +@@ -220,8 +220,7 @@ + umul_ppmm (ovfl, rtwos_bits, e, btwos); + if (ovfl) + { +- fprintf (stderr, "gmp: overflow in mpz type\n"); +- abort (); ++ __GMP_ALLOC_OVERFLOW_FUNC (); + } + + rtwos_limbs += rtwos_bits / GMP_NUMB_BITS; +@@ -382,8 +381,7 @@ + umul_ppmm (ovfl, ralloc, (bsize*GMP_NUMB_BITS - cnt + GMP_NAIL_BITS), e); + if (ovfl) + { +- fprintf (stderr, "gmp: overflow in mpz type\n"); +- abort (); ++ __GMP_ALLOC_OVERFLOW_FUNC (); + } + ralloc = ralloc / GMP_NUMB_BITS + 5; + +diff -ur gmp-6.2.1.orig/tal-reent.c gmp-6.2.1/tal-reent.c +--- gmp-6.2.1.orig/tal-reent.c 2020-11-14 19:45:09.000000000 +0100 ++++ gmp-6.2.1/tal-reent.c 2023-09-08 12:10:34.061357613 +0200 +@@ -61,6 +61,11 @@ + + total_size = size + HSIZ; + p = __GMP_ALLOCATE_FUNC_TYPE (total_size, char); ++ if (!p) ++ { ++ __GMP_ALLOC_OVERFLOW_FUNC (); ++ } + P->size = total_size; + P->next = *markp; + *markp = P; diff --git a/stdlib/GMP_jll/Project.toml b/stdlib/GMP_jll/Project.toml index e4af2a8674a51..9f3b917257bfa 100644 --- a/stdlib/GMP_jll/Project.toml +++ b/stdlib/GMP_jll/Project.toml @@ -1,6 +1,6 @@ name = "GMP_jll" uuid = "781609d7-10c4-51f6-84f2-b8444358ff6d" -version = "6.2.1+5" +version = "6.2.1+6" [deps] Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" diff --git a/test/gmp.jl b/test/gmp.jl index 5534c814ac79f..8bfe90ec7d9e4 100644 --- a/test/gmp.jl +++ b/test/gmp.jl @@ -11,6 +11,11 @@ ee = typemax(Int64) @test BigInt <: Signed @test big(1) isa Signed + if sizeof(Culong) >= 8 + @test_throws OutOfMemoryError big(96608869069402268615522366320733234710)^16374500563449903721 + @test_throws OutOfMemoryError 555555555555555555555555555555555555555555555555555^55555555555555555 + end + let x = big(1) @test signed(x) === x @test convert(Signed, x) === x From b9203ce52fc7cd58ebf3d4ce4e15789853cc626d Mon Sep 17 00:00:00 2001 From: Valentin Churavy Date: Mon, 11 Sep 2023 15:31:18 -0400 Subject: [PATCH 12/15] Fix Profiler signal listener test (#51272) The `close(t)` seems to be a typo. --- stdlib/Profile/test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/Profile/test/runtests.jl b/stdlib/Profile/test/runtests.jl index 2d6df81b1015d..95ec7f857dad7 100644 --- a/stdlib/Profile/test/runtests.jl +++ b/stdlib/Profile/test/runtests.jl @@ -200,7 +200,6 @@ if Sys.isbsd() || Sys.islinux() script = """ print(stderr, "started\n") eof(stdin) - close(t) """ iob = Base.BufferStream() notify_exit = Base.PipeEndpoint() @@ -232,6 +231,7 @@ if Sys.isbsd() || Sys.islinux() close(notify_exit) # notify test finished s = read(iob, String) # consume test output wait(p) # wait for test completion + @test success(p) close(t) catch close(notify_exit) From ad27e67b4f3b515c5c8795a4a098d95c792fcc3a Mon Sep 17 00:00:00 2001 From: Yichao Yu Date: Mon, 11 Sep 2023 17:15:25 -0400 Subject: [PATCH 13/15] Fix Markdown test from #49454 (#51268) Actually testing the output instead of printing to stdout. --- stdlib/Markdown/test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/Markdown/test/runtests.jl b/stdlib/Markdown/test/runtests.jl index 19d821a0254d7..84f0868747567 100644 --- a/stdlib/Markdown/test/runtests.jl +++ b/stdlib/Markdown/test/runtests.jl @@ -1185,7 +1185,7 @@ Base.show(io::IO, ::Struct49454) = let buf = IOBuffer() ctx = IOContext(buf, :color => true, :displaysize => (displaysize(buf)[1], 10)) - show(stdout, MIME("text/plain"), md""" + show(ctx, MIME("text/plain"), md""" text without $(Struct49454()) underline. """) lines = split(String(take!(buf)), '\n') From 5d82d8095042935be0eb044259098e0d7c695922 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Tue, 12 Sep 2023 11:14:30 +0900 Subject: [PATCH 14/15] add tfuncs for `[and|or]_int` intrinsics (#51266) So that they can be constant folded when either of argument is known to be `Core([false|true])`. It may help inference accuracy. --- base/compiler/tfuncs.jl | 26 ++++++++++++++++++++++++-- test/compiler/inference.jl | 8 ++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/base/compiler/tfuncs.jl b/base/compiler/tfuncs.jl index 39c930e8cfbeb..2f0b6711cf995 100644 --- a/base/compiler/tfuncs.jl +++ b/base/compiler/tfuncs.jl @@ -198,11 +198,33 @@ add_tfunc(div_float_fast, 2, 2, math_tfunc, 2) # bitwise operators # ----------------- +@nospecs and_int_tfunc(𝕃::AbstractLattice, x, y) = and_int_tfunc(widenlattice(𝕃), x, y) +@nospecs function and_int_tfunc(𝕃::ConstsLattice, x, y) + if isa(x, Const) && x.val === false && widenconst(y) === Bool + return Const(false) + elseif isa(y, Const) && y.val === false && widenconst(x) === Bool + return Const(false) + end + return and_int_tfunc(widenlattice(𝕃), x, y) +end +@nospecs and_int_tfunc(::JLTypeLattice, x, y) = widenconst(x) + +@nospecs or_int_tfunc(𝕃::AbstractLattice, x, y) = or_int_tfunc(widenlattice(𝕃), x, y) +@nospecs function or_int_tfunc(𝕃::ConstsLattice, x, y) + if isa(x, Const) && x.val === true && widenconst(y) === Bool + return Const(true) + elseif isa(y, Const) && y.val === true && widenconst(x) === Bool + return Const(true) + end + return or_int_tfunc(widenlattice(𝕃), x, y) +end +@nospecs or_int_tfunc(::JLTypeLattice, x, y) = widenconst(x) + @nospecs shift_tfunc(𝕃::AbstractLattice, x, y) = shift_tfunc(widenlattice(𝕃), x, y) @nospecs shift_tfunc(::JLTypeLattice, x, y) = widenconst(x) -add_tfunc(and_int, 2, 2, math_tfunc, 1) -add_tfunc(or_int, 2, 2, math_tfunc, 1) +add_tfunc(and_int, 2, 2, and_int_tfunc, 1) +add_tfunc(or_int, 2, 2, or_int_tfunc, 1) add_tfunc(xor_int, 2, 2, math_tfunc, 1) add_tfunc(not_int, 1, 1, math_tfunc, 0) # usually used as not_int(::Bool) to negate a condition add_tfunc(shl_int, 2, 2, shift_tfunc, 1) diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index 79dc6838a86fc..8c0c996f97738 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -5190,3 +5190,11 @@ foo51090(b) = return bar51090(b) @test Base.return_types() do Base.or_int(true, 1) end |> only === Union{} + +# [add|or]_int tfuncs +@test Base.return_types((Bool,)) do b + Val(Core.Intrinsics.and_int(b, false)) +end |> only == Val{false} +@test Base.return_types((Bool,)) do b + Val(Core.Intrinsics.or_int(true, b)) +end |> only == Val{true} From c07ef6b4da89751c4aeb6951a642c1a0bee9c98b Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Thu, 7 Sep 2023 13:29:19 +0100 Subject: [PATCH 15/15] add inline repl tab complete hints --- NEWS.md | 3 ++ stdlib/REPL/docs/src/index.md | 8 ++++- stdlib/REPL/src/LineEdit.jl | 58 ++++++++++++++++++++++++++++++++--- stdlib/REPL/src/options.jl | 3 ++ stdlib/REPL/test/repl.jl | 31 +++++++++++++++++++ 5 files changed, 97 insertions(+), 6 deletions(-) diff --git a/NEWS.md b/NEWS.md index 16afb8c168443..938bf9a84ae3b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -48,6 +48,9 @@ Standard library changes #### REPL +* Tab complete hints now show in lighter text while typing in the repl. To disable + set `Base.active_repl.options.hint_tab_completes = false` ([#51229]) + #### SuiteSparse diff --git a/stdlib/REPL/docs/src/index.md b/stdlib/REPL/docs/src/index.md index ce594d55863bc..67b64c6ca5168 100644 --- a/stdlib/REPL/docs/src/index.md +++ b/stdlib/REPL/docs/src/index.md @@ -312,7 +312,7 @@ Users should refer to `LineEdit.jl` to discover the available actions on key inp ## Tab completion -In both the Julian and help modes of the REPL, one can enter the first few characters of a function +In the Julian, pkg and help modes of the REPL, one can enter the first few characters of a function or type and then press the tab key to get a list all matches: ```julia-repl @@ -334,6 +334,12 @@ julia> mapfold[TAB] mapfoldl mapfoldr ``` +When a single complete tab-complete result is available a hint of the completion will show in a lighter color. +This can be disabled via `Base.active_repl.options.hint_tab_completes = false`. + +!!! compat "Julia 1.11" + Tab-complete hinting was added in Julia 1.11 + Like other components of the REPL, the search is case-sensitive: ```julia-repl diff --git a/stdlib/REPL/src/LineEdit.jl b/stdlib/REPL/src/LineEdit.jl index ff67e849fcc5a..6ba91e27ea8a3 100644 --- a/stdlib/REPL/src/LineEdit.jl +++ b/stdlib/REPL/src/LineEdit.jl @@ -97,6 +97,7 @@ mutable struct PromptState <: ModeState p::Prompt input_buffer::IOBuffer region_active::Symbol # :shift or :mark or :off + hint::Union{String,Nothing} undo_buffers::Vector{IOBuffer} undo_idx::Int ias::InputAreaState @@ -361,7 +362,7 @@ function show_completions(s::PromptState, completions::Vector{String}) end end -# Prompt Completions +# Prompt Completions & Hints function complete_line(s::MIState) set_action!(s, :complete_line) if complete_line(state(s), s.key_repeats, s.active_module) @@ -372,6 +373,36 @@ function complete_line(s::MIState) end end +function check_for_hint(s::MIState) + st = state(s) + options(st).hint_tab_completes || return nothing + completions, partial, should_complete = complete_line(st.p.complete, st, s.active_module)::Tuple{Vector{String},String,Bool} + if should_complete + if length(completions) == 1 + hint = only(completions)[sizeof(partial)+1:end] + if !isempty(hint) # completion on a complete name returns itself so check that there's something to hint + st.hint = hint + return refresh_line(s) + end + elseif length(completions) > 1 + p = common_prefix(completions) + if p in completions # i.e. complete `@time` even though `@time_imports` etc. exists + hint = p[sizeof(partial)+1:end] + if !isempty(hint) + st.hint = hint + return refresh_line(s) + end + end + end + end + if !isnothing(st.hint) + st.hint = "" # don't set to nothing here. That will be done in `maybe_show_hint` + return refresh_line(s) + else + return nothing + end +end + function complete_line(s::PromptState, repeats::Int, mod::Module) completions, partial, should_complete = complete_line(s.p.complete, s, mod)::Tuple{Vector{String},String,Bool} isempty(completions) && return false @@ -432,12 +463,29 @@ prompt_string(p::Prompt) = prompt_string(p.prompt) prompt_string(s::AbstractString) = s prompt_string(f::Function) = Base.invokelatest(f) +function maybe_show_hint(s::PromptState) + isa(s.hint, String) || return nothing + # The hint being "" then nothing is used to first clear a previous hint, then skip printing the hint + # the clear line cannot be printed each time because it breaks column movement + if isempty(s.hint) + print(terminal(s), "\e[0K") # clear remainder of line which had a hint + s.hint = nothing + else + Base.printstyled(terminal(s), s.hint, color=:light_black) + cmove_left(terminal(s), textwidth(s.hint)) + s.hint = "" # being "" signals to do one clear line remainder to clear the hint next time if still empty + end + return nothing +end + function refresh_multi_line(s::PromptState; kw...) if s.refresh_wait !== nothing close(s.refresh_wait) s.refresh_wait = nothing end - refresh_multi_line(terminal(s), s; kw...) + r = refresh_multi_line(terminal(s), s; kw...) + maybe_show_hint(s) + return r end refresh_multi_line(s::ModeState; kw...) = refresh_multi_line(terminal(s), s; kw...) refresh_multi_line(termbuf::TerminalBuffer, s::ModeState; kw...) = refresh_multi_line(termbuf, terminal(s), s; kw...) @@ -2424,8 +2472,8 @@ AnyDict( "\e\n" => "\e\r", "^_" => (s::MIState,o...)->edit_undo!(s), "\e_" => (s::MIState,o...)->edit_redo!(s), - # Simply insert it into the buffer by default - "*" => (s::MIState,data,c::StringLike)->(edit_insert(s, c)), + # Show hints at what tab complete would do by default + "*" => (s::MIState,data,c::StringLike)->(edit_insert(s, c); check_for_hint(s)), "^U" => (s::MIState,o...)->edit_kill_line_backwards(s), "^K" => (s::MIState,o...)->edit_kill_line_forwards(s), "^Y" => (s::MIState,o...)->edit_yank(s), @@ -2634,7 +2682,7 @@ end run_interface(::Prompt) = nothing init_state(terminal, prompt::Prompt) = - PromptState(terminal, prompt, IOBuffer(), :off, IOBuffer[], 1, InputAreaState(1, 1), + PromptState(terminal, prompt, IOBuffer(), :off, nothing, IOBuffer[], 1, InputAreaState(1, 1), #=indent(spaces)=# -1, Threads.SpinLock(), 0.0, -Inf, nothing) function init_state(terminal, m::ModalInterface) diff --git a/stdlib/REPL/src/options.jl b/stdlib/REPL/src/options.jl index 3ce0ab6ff00dc..1fb2c654c7df2 100644 --- a/stdlib/REPL/src/options.jl +++ b/stdlib/REPL/src/options.jl @@ -27,6 +27,7 @@ mutable struct Options auto_indent_time_threshold::Float64 # refresh after time delay auto_refresh_time_delay::Float64 + hint_tab_completes::Bool # default IOContext settings at the REPL iocontext::Dict{Symbol,Any} end @@ -47,6 +48,7 @@ Options(; auto_indent_bracketed_paste = false, auto_indent_time_threshold = 0.005, auto_refresh_time_delay = Sys.iswindows() ? 0.05 : 0.0, + hint_tab_completes = true, iocontext = Dict{Symbol,Any}()) = Options(hascolor, extra_keymap, tabwidth, kill_ring_max, region_animation_duration, @@ -55,6 +57,7 @@ Options(; backspace_align, backspace_adjust, confirm_exit, auto_indent, auto_indent_tmp_off, auto_indent_bracketed_paste, auto_indent_time_threshold, auto_refresh_time_delay, + hint_tab_completes, iocontext) # for use by REPLs not having an options field diff --git a/stdlib/REPL/test/repl.jl b/stdlib/REPL/test/repl.jl index 20f07864a275b..34fd74a93c9d2 100644 --- a/stdlib/REPL/test/repl.jl +++ b/stdlib/REPL/test/repl.jl @@ -1670,3 +1670,34 @@ fake_repl() do stdin_write, stdout_read, repl wait(repltask) @test contains(txt, "Some type information was truncated. Use `show(err)` to see complete types.") end + +fake_repl() do stdin_write, stdout_read, repl + repltask = @async begin + REPL.run_repl(repl) + end + write(stdin_write, "reada") + s1 = readuntil(stdout_read, "reada") # typed + s2 = readuntil(stdout_read, "vailable") # partial hint + + write(stdin_write, "x") # "readax" doesn't tab complete so no hint + # we can't use readuntil given this doesn't print, so just wait for the hint state to be reset + while LineEdit.state(repl.mistate).hint !== nothing + sleep(0.1) + end + @test LineEdit.state(repl.mistate).hint === nothing + + write(stdin_write, "\b") # only tab complete while typing forward + while LineEdit.state(repl.mistate).hint !== nothing + sleep(0.1) + end + @test LineEdit.state(repl.mistate).hint === nothing + + write(stdin_write, "v") + s3 = readuntil(stdout_read, "ailable") # partial hint + + write(stdin_write, "\t") + s4 = readuntil(stdout_read, "readavailable") # full completion is reprinted + + write(stdin_write, "\x15\x04") + Base.wait(repltask) +end