From be5bc79fbb6e0b19a30533d493b5594a3c064c44 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sat, 15 Mar 2025 09:33:41 -0400 Subject: [PATCH 01/23] loading: fix ccall signature in _include_from_serialized (#57776) This still sort of errored correctly anyways (after breakage added from PR #56499), but that behavior should not be relied upon optimizations not breaking it when this is providing incorrect info to the compiler. Fix #57459 (cherry picked from commit a5abb6fb0e570ae84721e1341086cdf22c8faa37) --- base/loading.jl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/base/loading.jl b/base/loading.jl index de212f79e93b7..b8962eeaa4d1c 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -1267,17 +1267,21 @@ function _include_from_serialized(pkg::PkgId, path::String, ocachepath::Union{No sv = try if ocachepath !== nothing @debug "Loading object cache file $ocachepath for $(repr("text/plain", pkg))" - ccall(:jl_restore_package_image_from_file, Ref{SimpleVector}, (Cstring, Any, Cint, Cstring, Cint), + ccall(:jl_restore_package_image_from_file, Any, (Cstring, Any, Cint, Cstring, Cint), ocachepath, depmods, #=completeinfo=#false, pkg.name, ignore_native) else @debug "Loading cache file $path for $(repr("text/plain", pkg))" - ccall(:jl_restore_incremental, Ref{SimpleVector}, (Cstring, Any, Cint, Cstring), + ccall(:jl_restore_incremental, Any, (Cstring, Any, Cint, Cstring), path, depmods, #=completeinfo=#false, pkg.name) end finally lock(require_lock) end + if isa(sv, Exception) + return sv + end + sv = sv::SimpleVector edges = sv[3]::Vector{Any} ext_edges = sv[4]::Union{Nothing,Vector{Any}} extext_methods = sv[5]::Vector{Any} From 6f6157a296b4fd46c2b12a51340104986bf5fe34 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Wed, 20 Aug 2025 08:10:38 -0400 Subject: [PATCH 02/23] Make `haskey(::@Kwargs{item::Bool}, :item)` constant-fold (#59320) Resolves https://github.com/JuliaLang/julia/issues/59269. Resolves https://github.com/JuliaLang/julia/issues/59292. --- Compiler/test/inference.jl | 7 +++++++ base/essentials.jl | 4 ++-- base/iterators.jl | 20 ++++++++++---------- base/namedtuple.jl | 6 +++--- base/show.jl | 6 ++++-- test/namedtuple.jl | 4 ++++ test/show.jl | 2 +- 7 files changed, 31 insertions(+), 18 deletions(-) diff --git a/Compiler/test/inference.jl b/Compiler/test/inference.jl index fb17f1991dc45..a4294e2e45f6b 100644 --- a/Compiler/test/inference.jl +++ b/Compiler/test/inference.jl @@ -6291,3 +6291,10 @@ end <: Bool @test Base.infer_return_type((Module,Symbol,Vector{Any})) do m, n, xs Core.get_binding_type(m, n, xs...) end <: Type + +# issue #59269 +function haskey_inference_test() + kwargs = Core.compilerbarrier(:const, Base.pairs((; item = false))) + return haskey(kwargs, :item) ? nothing : Any[] +end +@inferred haskey_inference_test() diff --git a/base/essentials.jl b/base/essentials.jl index bf48f24f5234c..b817e53ec6c4d 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -489,9 +489,9 @@ end Pairs{K, V, I, A}(data, itr) where {K, V, I, A} = $(Expr(:new, :(Pairs{K, V, I, A}), :(data isa A ? data : convert(A, data)), :(itr isa I ? itr : convert(I, itr)))) Pairs{K, V}(data::A, itr::I) where {K, V, I, A} = $(Expr(:new, :(Pairs{K, V, I, A}), :data, :itr)) Pairs{K}(data::A, itr::I) where {K, I, A} = $(Expr(:new, :(Pairs{K, eltype(A), I, A}), :data, :itr)) - Pairs(data::A, itr::I) where {I, A} = $(Expr(:new, :(Pairs{eltype(I), eltype(A), I, A}), :data, :itr)) + Pairs(data::A, itr::I) where {I, A} = $(Expr(:new, :(Pairs{I !== Nothing ? eltype(I) : keytype(A), eltype(A), I, A}), :data, :itr)) end -pairs(::Type{NamedTuple}) = Pairs{Symbol, V, NTuple{N, Symbol}, NamedTuple{names, T}} where {V, N, names, T<:NTuple{N, Any}} +pairs(::Type{NamedTuple}) = Pairs{Symbol, V, Nothing, NT} where {V, NT <: NamedTuple} """ Base.Pairs(values, keys) <: AbstractDict{eltype(keys), eltype(values)} diff --git a/base/iterators.jl b/base/iterators.jl index 29473561c452a..f7ae8138f6856 100644 --- a/base/iterators.jl +++ b/base/iterators.jl @@ -267,7 +267,7 @@ pairs(::IndexLinear, A::AbstractArray) = Pairs(A, LinearIndices(A)) # preserve indexing capabilities for known indexable types # faster than zip(keys(a), values(a)) for arrays pairs(tuple::Tuple) = Pairs{Int}(tuple, keys(tuple)) -pairs(nt::NamedTuple) = Pairs{Symbol}(nt, keys(nt)) +pairs(nt::NamedTuple) = Pairs{Symbol}(nt, nothing) pairs(v::Core.SimpleVector) = Pairs(v, LinearIndices(v)) pairs(A::AbstractVector) = pairs(IndexLinear(), A) # pairs(v::Pairs) = v # listed for reference, but already defined from being an AbstractDict @@ -275,40 +275,40 @@ pairs(A::AbstractVector) = pairs(IndexLinear(), A) pairs(::IndexCartesian, A::AbstractArray) = Pairs(A, Base.CartesianIndices(axes(A))) pairs(A::AbstractArray) = pairs(IndexCartesian(), A) -length(v::Pairs) = length(getfield(v, :itr)) -axes(v::Pairs) = axes(getfield(v, :itr)) -size(v::Pairs) = size(getfield(v, :itr)) +length(v::Pairs) = length(keys(v)) +axes(v::Pairs) = axes(keys(v)) +size(v::Pairs) = size(keys(v)) Base.@eval @propagate_inbounds function _pairs_elt(p::Pairs{K, V}, idx) where {K, V} return $(Expr(:new, :(Pair{K, V}), :idx, :(getfield(p, :data)[idx]))) end @propagate_inbounds function iterate(p::Pairs{K, V}, state...) where {K, V} - x = iterate(getfield(p, :itr), state...) + x = iterate(keys(p), state...) x === nothing && return x idx, next = x return (_pairs_elt(p, idx), next) end -@propagate_inbounds function iterate(r::Reverse{<:Pairs}, state=(reverse(getfield(r.itr, :itr)),)) +@propagate_inbounds function iterate(r::Reverse{<:Pairs}, state=(reverse(keys(r.itr)),)) x = iterate(state...) x === nothing && return x idx, next = x return (_pairs_elt(r.itr, idx), (state[1], next)) end -@inline isdone(v::Pairs, state...) = isdone(getfield(v, :itr), state...) +@inline isdone(v::Pairs, state...) = isdone(keys(v), state...) IteratorSize(::Type{<:Pairs{<:Any, <:Any, I}}) where {I} = IteratorSize(I) IteratorSize(::Type{<:Pairs{<:Any, <:Any, <:AbstractUnitRange, <:Tuple}}) = HasLength() function last(v::Pairs{K, V}) where {K, V} - idx = last(getfield(v, :itr)) + idx = last(keys(v)) return Pair{K, V}(idx, v[idx]) end -haskey(v::Pairs, key) = (key in getfield(v, :itr)) -keys(v::Pairs) = getfield(v, :itr) +haskey(v::Pairs, key) = key in keys(v) +keys(v::Pairs) = getfield(v, :itr) === nothing ? keys(getfield(v, :data)) : getfield(v, :itr) values(v::Pairs) = getfield(v, :data) # TODO: this should be a view of data subset by itr getindex(v::Pairs, key) = getfield(v, :data)[key] setindex!(v::Pairs, value, key) = (getfield(v, :data)[key] = value; v) diff --git a/base/namedtuple.jl b/base/namedtuple.jl index f71b13852b953..37f3a3ef8436b 100644 --- a/base/namedtuple.jl +++ b/base/namedtuple.jl @@ -343,7 +343,7 @@ merge(a::NamedTuple, b::NamedTuple{()}) = a merge(a::NamedTuple{()}, b::NamedTuple{()}) = a merge(a::NamedTuple{()}, b::NamedTuple) = b -merge(a::NamedTuple, b::Iterators.Pairs{<:Any,<:Any,<:Any,<:NamedTuple}) = merge(a, getfield(b, :data)) +merge(a::NamedTuple, b::Iterators.Pairs{<:Any,<:Any,Nothing,<:NamedTuple}) = merge(a, getfield(b, :data)) merge(a::NamedTuple, b::Iterators.Zip{<:Tuple{Any,Any}}) = merge(a, NamedTuple{Tuple(b.is[1])}(b.is[2])) @@ -535,7 +535,7 @@ when it is printed in the stack trace view. ```julia julia> @Kwargs{init::Int} # the internal representation of keyword arguments -Base.Pairs{Symbol, Int64, Tuple{Symbol}, @NamedTuple{init::Int64}} +Base.Pairs{Symbol, Int64, Nothing, @NamedTuple{init::Int64}} julia> sum("julia"; init=1) ERROR: MethodError: no method matching +(::Char, ::Char) @@ -578,7 +578,7 @@ Stacktrace: macro Kwargs(ex) return :(let NT = @NamedTuple $ex - Base.Pairs{keytype(NT),eltype(NT),typeof(NT.parameters[1]),NT} + Base.Pairs{keytype(NT),eltype(NT),Nothing,NT} end) end diff --git a/base/show.jl b/base/show.jl index 8ee211b882eec..3d38770c2e2a7 100644 --- a/base/show.jl +++ b/base/show.jl @@ -1106,6 +1106,8 @@ function show_type_name(io::IO, tn::Core.TypeName) end function maybe_kws_nt(x::DataType) + # manually-written version of + # x <: (Pairs{Symbol, eltype(NT), Nothing, NT} where NT <: NamedTuple) x.name === typename(Pairs) || return nothing length(x.parameters) == 4 || return nothing x.parameters[1] === Symbol || return nothing @@ -1115,7 +1117,7 @@ function maybe_kws_nt(x::DataType) types isa DataType || return nothing x.parameters[2] === eltype(p4) || return nothing isa(syms, Tuple) || return nothing - x.parameters[3] === typeof(syms) || return nothing + x.parameters[3] === Nothing || return nothing return p4 end return nothing @@ -3313,7 +3315,7 @@ function Base.showarg(io::IO, r::Iterators.Pairs{<:Integer, <:Any, <:Any, T}, to print(io, "pairs(IndexLinear(), ::", T, ")") end -function Base.showarg(io::IO, r::Iterators.Pairs{Symbol, <:Any, <:Any, T}, toplevel) where {T <: NamedTuple} +function Base.showarg(io::IO, r::Iterators.Pairs{Symbol, <:Any, Nothing, T}, toplevel) where {T <: NamedTuple} print(io, "pairs(::NamedTuple)") end diff --git a/test/namedtuple.jl b/test/namedtuple.jl index b8dba5c06422e..0f54196879a43 100644 --- a/test/namedtuple.jl +++ b/test/namedtuple.jl @@ -163,6 +163,10 @@ end @test merge(NamedTuple(), [:a=>1, :b=>2, :c=>3, :a=>4, :c=>5]) == (a=4, b=2, c=5) @test merge((c=0, z=1), [:a=>1, :b=>2, :c=>3, :a=>4, :c=>5]) == (c=5, z=1, a=4, b=2) +# https://github.com/JuliaLang/julia/issues/59292 +@test merge((; a = 1), Base.Pairs((; b = 2, c = 3), (:b,))) == (a = 1, b = 2) +@test merge((; a = 1), Base.pairs((; b = 2, c = 3))) == (a = 1, b = 2, c = 3) + @test keys((a=1, b=2, c=3)) == (:a, :b, :c) @test keys(NamedTuple()) == () @test keys((a=1,)) == (:a,) diff --git a/test/show.jl b/test/show.jl index 7c51768579042..898ff7578a3e4 100644 --- a/test/show.jl +++ b/test/show.jl @@ -1448,7 +1448,7 @@ test_repr("(:).a") @test repr(@NamedTuple{var"#"::Int64}) == "@NamedTuple{var\"#\"::Int64}" # Test general printing of `Base.Pairs` (it should not use the `@Kwargs` macro syntax) -@test repr(@Kwargs{init::Int}) == "Base.Pairs{Symbol, $Int, Tuple{Symbol}, @NamedTuple{init::$Int}}" +@test repr(@Kwargs{init::Int}) == "Base.Pairs{Symbol, $Int, Nothing, @NamedTuple{init::$Int}}" @testset "issue #42931" begin @test repr(NTuple{4, :A}) == "Tuple{:A, :A, :A, :A}" From 172a745230a13b8f74a39898728301386b1700f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Thu, 21 Aug 2025 06:29:00 +0200 Subject: [PATCH 03/23] Fix JET-reported issues in `BinaryPlatforms.triplet(::AbstractPlatform)` (#59343) The issue is that JET reported that in `libgfortran_version(p).major` the first arg of `getproperty` could be `nothing`. This is already checked in the previous line, but in a way that the compiler cannot remember until that call. Putting it into a variable should fix that. It would be great if this could get backported to at least 1.12 (1.10 and 1.11 would also be great), since that is where people try to use JET for their packages, and this reduces the Base noise in the output. --- base/binaryplatforms.jl | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/base/binaryplatforms.jl b/base/binaryplatforms.jl index 598b618f0d1ed..c4c65504be424 100644 --- a/base/binaryplatforms.jl +++ b/base/binaryplatforms.jl @@ -520,14 +520,17 @@ function triplet(p::AbstractPlatform) ) # Tack on optional compiler ABI flags - if libgfortran_version(p) !== nothing - str = string(str, "-libgfortran", libgfortran_version(p).major) + libgfortran_version_ = libgfortran_version(p) + if libgfortran_version_ !== nothing + str = string(str, "-libgfortran", libgfortran_version_.major) end - if cxxstring_abi(p) !== nothing - str = string(str, "-", cxxstring_abi(p)) + cxxstring_abi_ = cxxstring_abi(p) + if cxxstring_abi_ !== nothing + str = string(str, "-", cxxstring_abi_) end - if libstdcxx_version(p) !== nothing - str = string(str, "-libstdcxx", libstdcxx_version(p).patch) + libstdcxx_version_ = libstdcxx_version(p) + if libstdcxx_version_ !== nothing + str = string(str, "-libstdcxx", libstdcxx_version_.patch) end # Tack on all extra tags From 6eb5f84651d4c317245a842b72efba356cb16070 Mon Sep 17 00:00:00 2001 From: Neven Sajko <4944410+nsajko@users.noreply.github.com> Date: Thu, 21 Aug 2025 09:25:38 +0200 Subject: [PATCH 04/23] `@nospecialize` for `string_index_err` (#57604) The fields of `StringIndexError` are abstractly typed, so there's no reason to specialize on a concrete type. The change seems like it could prevent some invalidation on loading user code. --------- Co-authored-by: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> --- base/strings/string.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/strings/string.jl b/base/strings/string.jl index 79ec12d11cb94..32fd47b45cf49 100644 --- a/base/strings/string.jl +++ b/base/strings/string.jl @@ -7,9 +7,9 @@ An error occurred when trying to access `str` at index `i` that is not valid. """ struct StringIndexError <: Exception string::AbstractString - index::Integer + index::Int end -@noinline string_index_err(s::AbstractString, i::Integer) = +@noinline string_index_err((@nospecialize s::AbstractString), i::Integer) = throw(StringIndexError(s, Int(i))) function Base.showerror(io::IO, exc::StringIndexError) s = exc.string From 883e006e30dbb763de8b3b9867b9aa8a34e132be Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Mon, 25 Aug 2025 10:15:54 -0400 Subject: [PATCH 05/23] =?UTF-8?q?=F0=9F=A4=96=20[backports-release-1.12]?= =?UTF-8?q?=20Bump=20the=20LinearAlgebra=20stdlib=20from=206cc0405=20to=20?= =?UTF-8?q?b5a8bb0=20(#59388)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../md5 | 1 - .../sha512 | 1 - .../md5 | 1 + .../sha512 | 1 + stdlib/LinearAlgebra.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/LinearAlgebra-6cc040592fd509ee048658e9afb8a99a2dc20e1b.tar.gz/md5 delete mode 100644 deps/checksums/LinearAlgebra-6cc040592fd509ee048658e9afb8a99a2dc20e1b.tar.gz/sha512 create mode 100644 deps/checksums/LinearAlgebra-b5a8bb07059f0d499c493c6db01980b060836f5a.tar.gz/md5 create mode 100644 deps/checksums/LinearAlgebra-b5a8bb07059f0d499c493c6db01980b060836f5a.tar.gz/sha512 diff --git a/deps/checksums/LinearAlgebra-6cc040592fd509ee048658e9afb8a99a2dc20e1b.tar.gz/md5 b/deps/checksums/LinearAlgebra-6cc040592fd509ee048658e9afb8a99a2dc20e1b.tar.gz/md5 deleted file mode 100644 index 585185b3c2983..0000000000000 --- a/deps/checksums/LinearAlgebra-6cc040592fd509ee048658e9afb8a99a2dc20e1b.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -39c0cb64a6c4226f8cb07518f592a8bc diff --git a/deps/checksums/LinearAlgebra-6cc040592fd509ee048658e9afb8a99a2dc20e1b.tar.gz/sha512 b/deps/checksums/LinearAlgebra-6cc040592fd509ee048658e9afb8a99a2dc20e1b.tar.gz/sha512 deleted file mode 100644 index 41693dd5c7625..0000000000000 --- a/deps/checksums/LinearAlgebra-6cc040592fd509ee048658e9afb8a99a2dc20e1b.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -31563375775a85fa5ae1f6584f0ebc1ffef8b66a2c76ea74111b21c5d6d171189768d40cf6a4decc203845c8d0c789da6688ad9a15ec9d5ee8e7700e1e08715b diff --git a/deps/checksums/LinearAlgebra-b5a8bb07059f0d499c493c6db01980b060836f5a.tar.gz/md5 b/deps/checksums/LinearAlgebra-b5a8bb07059f0d499c493c6db01980b060836f5a.tar.gz/md5 new file mode 100644 index 0000000000000..b8651ee8f2d46 --- /dev/null +++ b/deps/checksums/LinearAlgebra-b5a8bb07059f0d499c493c6db01980b060836f5a.tar.gz/md5 @@ -0,0 +1 @@ +f41f7e4247fddb5531dea530bee83024 diff --git a/deps/checksums/LinearAlgebra-b5a8bb07059f0d499c493c6db01980b060836f5a.tar.gz/sha512 b/deps/checksums/LinearAlgebra-b5a8bb07059f0d499c493c6db01980b060836f5a.tar.gz/sha512 new file mode 100644 index 0000000000000..6523086dbd0a1 --- /dev/null +++ b/deps/checksums/LinearAlgebra-b5a8bb07059f0d499c493c6db01980b060836f5a.tar.gz/sha512 @@ -0,0 +1 @@ +d2596e62f75841be0da013c8c41708577ae2527d3564d95081385d77fc00da514a46f25bbb42304b76127890018358cb191c80c18ba57818c2fde8ebedde260b diff --git a/stdlib/LinearAlgebra.version b/stdlib/LinearAlgebra.version index 10e03e5e0f103..6ee231d7dd649 100644 --- a/stdlib/LinearAlgebra.version +++ b/stdlib/LinearAlgebra.version @@ -1,4 +1,4 @@ LINEARALGEBRA_BRANCH = release-1.12 -LINEARALGEBRA_SHA1 = 6cc040592fd509ee048658e9afb8a99a2dc20e1b +LINEARALGEBRA_SHA1 = b5a8bb07059f0d499c493c6db01980b060836f5a LINEARALGEBRA_GIT_URL := https://github.com/JuliaLang/LinearAlgebra.jl.git LINEARALGEBRA_TAR_URL = https://api.github.com/repos/JuliaLang/LinearAlgebra.jl/tarball/$1 From 3220a81475c18f790015c930aa44701415dcb3ca Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Tue, 8 Apr 2025 15:45:54 -0400 Subject: [PATCH 06/23] Make delete_binding operate in the latest world (#58043) Fixes #58016 --- src/module.c | 18 +++++++++++------- test/rebinding.jl | 9 +++++++++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/module.c b/src/module.c index b6ed80e712c7e..b5d3e785bc96c 100644 --- a/src/module.c +++ b/src/module.c @@ -1775,16 +1775,20 @@ JL_DLLEXPORT void jl_disable_binding(jl_globalref_t *gr) jl_binding_t *b = gr->binding; if (!b) b = jl_get_module_binding(gr->mod, gr->name, 1); - jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age); - if (jl_binding_kind(bpart) == PARTITION_KIND_GUARD) { - // Already guard + for (;;) { + jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_atomic_load_acquire(&jl_world_counter)); + + if (jl_binding_kind(bpart) == PARTITION_KIND_GUARD) { + // Already guard + return; + } + + if (!jl_replace_binding(b, bpart, NULL, PARTITION_KIND_GUARD)) + continue; + return; } - - for (;;) - if (jl_replace_binding(b, bpart, NULL, PARTITION_KIND_GUARD)) - break; } JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var) diff --git a/test/rebinding.jl b/test/rebinding.jl index 1c2a4d7a0b91c..56bde53b7b746 100644 --- a/test/rebinding.jl +++ b/test/rebinding.jl @@ -383,3 +383,12 @@ end # M3 connects all, so we should have a single partition @test access_and_count(:afterM3) == 1 + +# Test that delete_binding in an outdated world age works +module BindingTestModule; end +function create_and_delete_binding() + Core.eval(BindingTestModule, :(const x = 1)) + Base.delete_binding(BindingTestModule, :x) +end +create_and_delete_binding() +@test Base.binding_kind(BindingTestModule, :x) == Base.PARTITION_KIND_GUARD From 66b6db726140f8491582641e6e681bd5cb3fa628 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sat, 23 Aug 2025 03:12:10 -0400 Subject: [PATCH 07/23] bpart: Fix reresolution logic on export value changes (#59368) Fixes #59272. This code was originally introduced in e7efe42ece419c04d170887d856609286e63836b. The design of the binding partitions underwent several changes, so I'm not fully sure if it was correct at the time, but regardless, it was rendered incorrect by 60a9f6992d82789e23a1e71f1e3c7402b1483b4f. In the new design, even a change to the value of a binding (not just its visibility) can affect the resolution outcome, so a full re-resolution is always required. Fix identified by Claude (in one of several rollouts). Correct fix among them identified by me. Actual change/test by me. --- base/invalidation.jl | 4 +--- test/rebinding.jl | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/base/invalidation.jl b/base/invalidation.jl index b55b09e29961d..4132231d9e852 100644 --- a/base/invalidation.jl +++ b/base/invalidation.jl @@ -155,9 +155,7 @@ function invalidate_code_for_globalref!(b::Core.Binding, invalidated_bpart::Core latest_bpart = user_binding.partitions latest_bpart.max_world == typemax(UInt) || continue is_some_implicit(binding_kind(latest_bpart)) || continue - new_bpart = need_to_invalidate_export ? - ccall(:jl_maybe_reresolve_implicit, Any, (Any, Csize_t), user_binding, new_max_world) : - latest_bpart + new_bpart = ccall(:jl_maybe_reresolve_implicit, Any, (Any, Csize_t), user_binding, new_max_world) if need_to_invalidate_code || new_bpart !== latest_bpart push!(queued_bindings, (convert(Core.Binding, user_binding), latest_bpart, new_bpart)) end diff --git a/test/rebinding.jl b/test/rebinding.jl index 56bde53b7b746..fa1f72cadfe4a 100644 --- a/test/rebinding.jl +++ b/test/rebinding.jl @@ -392,3 +392,19 @@ function create_and_delete_binding() end create_and_delete_binding() @test Base.binding_kind(BindingTestModule, :x) == Base.PARTITION_KIND_GUARD + +# Test that we properly invalidate bindings if the value changes, not just the +# export status (#59272) +module Invalidate59272 + using Test + module Foo + export Bar + struct Bar + # x + end + end + using .Foo + @test isa(Bar(), Foo.Bar) + Core.eval(Foo, :(struct Bar; x; end)) + @test Bar(1) == Foo.Bar(1) +end From 4aca0d6d0d53aa84420555928242c4771654a72b Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Mon, 18 Aug 2025 12:58:11 -0400 Subject: [PATCH 08/23] Include inference time in `--trace-compile-timing` (#59220) It's important for this measurement to include indirect compilation (not just "self" time), since the `--trace-compile` log only reports compilation triggers / entrypoints (not all compiled code). (cherry picked from commit 888c2c325272d8a3498d18165eb3b9ddd6910a3d) --- src/gf.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/gf.c b/src/gf.c index 0757614b390db..01b6ce69b4724 100644 --- a/src/gf.c +++ b/src/gf.c @@ -3519,9 +3519,8 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t } JL_GC_PUSH1(&codeinst); - double compile_time = jl_hrtime(); int did_compile = jl_compile_codeinst(codeinst); - compile_time = jl_hrtime() - compile_time; + double compile_time = jl_hrtime() - start; if (jl_atomic_load_relaxed(&codeinst->invoke) == NULL) { // Something went wrong. Bail to the fallback path. From daa0b9eb986303f8c524bedae9977356be6dd153 Mon Sep 17 00:00:00 2001 From: Adam Wheeler Date: Tue, 19 Aug 2025 17:12:06 -0400 Subject: [PATCH 09/23] Update the developer docs to reflect the use of JuliaSyntax.jl (#59300) [The "parsing" section of the "eval" dev docs page](https://docs.julialang.org/en/v1/devdocs/eval/#dev-parsing) was not updated when JuliaSyntax.jl was adopted in 1.10. This updates the text to reflect that it is the default parser and briefly mentions how to switch back. (cherry picked from commit ec272746d5e31d8c49ce079b6dc7177f1104eb14) --- doc/src/devdocs/eval.md | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/doc/src/devdocs/eval.md b/doc/src/devdocs/eval.md index 8f2fd68159676..21ec343f7f6be 100644 --- a/doc/src/devdocs/eval.md +++ b/doc/src/devdocs/eval.md @@ -62,25 +62,11 @@ The 10,000 foot view of the whole process is as follows: ## [Parsing](@id dev-parsing) -The Julia parser is a small lisp program written in femtolisp, the source-code for which is distributed -inside Julia in [src/flisp](https://github.com/JuliaLang/julia/tree/master/src/flisp). - -The interface functions for this are primarily defined in [`jlfrontend.scm`](https://github.com/JuliaLang/julia/blob/master/src/jlfrontend.scm). -The code in [`ast.c`](https://github.com/JuliaLang/julia/blob/master/src/ast.c) handles this handoff -on the Julia side. - -The other relevant files at this stage are [`julia-parser.scm`](https://github.com/JuliaLang/julia/blob/master/src/julia-parser.scm), -which handles tokenizing Julia code and turning it into an AST, and [`julia-syntax.scm`](https://github.com/JuliaLang/julia/blob/master/src/julia-syntax.scm), -which handles transforming complex AST representations into simpler, "lowered" AST representations -which are more suitable for analysis and execution. - -If you want to test the parser without re-building Julia in its entirety, you can run the frontend -on its own as follows: - - $ cd src - $ flisp/flisp - > (load "jlfrontend.scm") - > (jl-parse-file "") +By default, Julia uses [JuliaSyntax.jl](https://github.com/JuliaLang/JuliaSyntax.jl) to produce the +AST. Historically, it used a small lisp program written in femtolisp, the source-code for which is +distributed inside Julia in [src/flisp](https://github.com/JuliaLang/julia/tree/master/src/flisp). +If the `JULIA_USE_FLISP_PARSER` environment variable is set to `1`, the old parser will be used +instead. ## [Macro Expansion](@id dev-macro-expansion) From 2e45512244d7490442958abb159b9c8f35188418 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Thu, 21 Aug 2025 02:24:43 -0500 Subject: [PATCH 10/23] Log a backtrace on entrance to type inference (#58124) (cherry picked from commit fc0017f1c06632803103a99e6b5032031562705e) --- base/stacktraces.jl | 2 +- doc/src/devdocs/diagnostics.md | 37 ++++++++++++++++++++++++++++++++++ src/gf.c | 8 ++++++++ src/julia.h | 2 ++ src/julia_internal.h | 1 + src/staticdata_utils.c | 32 +++++++++++++++++++++++++++++ test/stacktraces.jl | 36 +++++++++++++++++++++++++++++++++ 7 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 doc/src/devdocs/diagnostics.md diff --git a/base/stacktraces.jl b/base/stacktraces.jl index 806c9468efed4..34af576737b33 100644 --- a/base/stacktraces.jl +++ b/base/stacktraces.jl @@ -365,4 +365,4 @@ function from(frame::StackFrame, m::Module) return parentmodule(frame) === m end -end +end # module StackTraces diff --git a/doc/src/devdocs/diagnostics.md b/doc/src/devdocs/diagnostics.md new file mode 100644 index 0000000000000..386f65db2e665 --- /dev/null +++ b/doc/src/devdocs/diagnostics.md @@ -0,0 +1,37 @@ +# Diagnostics used by the package ecosystem + +This page documents "hooks" embedded in Julia that are primarily used by +external tools. Many of these tools are designed to perform analyses that are +too complicated to be made part of Julia proper. + +## SnoopCompile + +SnoopCompile "snoops" on Julia's compiler to extract information for analysis +about invalidations and type-inference. There are a few internals it uses for +different purposes: + +- recording invalidations: `Base.StaticData.debug_method_invalidation` and + `ccall(:jl_debug_method_invalidation, ...)`: these record different modes of + invalidation. Users of SnoopCompile will transiently turn these on when, e.g., + loading packages. Each produces a standard log format; messing with the log + format might require a complementary pull request to SnoopCompile. + SnoopCompile will process these logs and generate trees of invalidated + CodeInstances that are attributable to specific changes in the method tables + or bindings. +- observing inference: `ccall(:jl_set_newly_inferred, ...)` and + `ccall(:jl_set_inference_entrance_backtraces, ...)`: these are used to + understand how inference gets triggered. The main purpose is to allow + performance diagnostics to understand sources of TTFX. The second of these + `ccall`s records a backtrace on every entrance to type-inference, so that + SnoopCompile can determine the caller of a dynamically-dispatched call. This + is needed to attribute "cause" for new type inference. + + The `jl_set_inference_entrance_backtraces` function accepts an array where + inference entrance events will be recorded. Each inference event stores two + consecutive array elements: first the `CodeInstance` object, then the + backtrace representation. So for N inference events, the array will contain 2N + elements arranged as: `[ci₁, bt₁, ci₂, bt₂, ..., ciₙ, btₙ]`. + + Note that the backtrace elements `btᵢ` contain raw backtrace data that + typically needs to be processed using `stacktrace(Base._reformat_bt(btᵢ...))`. + to convert them into a usable stack trace format for analysis. diff --git a/src/gf.c b/src/gf.c index 01b6ce69b4724..37d78cdaa2cc3 100644 --- a/src/gf.c +++ b/src/gf.c @@ -492,6 +492,14 @@ jl_code_instance_t *jl_type_infer(jl_method_instance_t *mi, size_t world, uint8_ if (ci && !jl_is_code_instance(ci)) { ci = NULL; } + + // Record inference entrance backtrace if enabled + if (ci) { + JL_GC_PUSH1(&ci); + jl_push_inference_entrance_backtraces((jl_value_t*)ci); + JL_GC_POP(); + } + JL_GC_POP(); #endif diff --git a/src/julia.h b/src/julia.h index 9bbdb2a092b97..34b2d79259ede 100644 --- a/src/julia.h +++ b/src/julia.h @@ -2274,6 +2274,8 @@ JL_DLLEXPORT jl_value_t *jl_object_top_module(jl_value_t* v) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_set_newly_inferred(jl_value_t *newly_inferred); JL_DLLEXPORT void jl_push_newly_inferred(jl_value_t *ci); +JL_DLLEXPORT void jl_set_inference_entrance_backtraces(jl_value_t *inference_entrance_backtraces); +JL_DLLEXPORT void jl_push_inference_entrance_backtraces(jl_value_t *ci); JL_DLLEXPORT void jl_write_compiler_output(void); // parsing diff --git a/src/julia_internal.h b/src/julia_internal.h index e9fc24dda22ca..9473f6be4b898 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -1494,6 +1494,7 @@ size_t rec_backtrace_ctx(jl_bt_element_t *bt_data, size_t maxsize, bt_context_t size_t rec_backtrace_ctx_dwarf(jl_bt_element_t *bt_data, size_t maxsize, bt_context_t *ctx, jl_gcframe_t *pgcstack) JL_NOTSAFEPOINT; #endif JL_DLLEXPORT jl_value_t *jl_get_backtrace(void); +JL_DLLEXPORT jl_value_t *jl_backtrace_from_here(int returnsp, int skip); void jl_critical_error(int sig, int si_code, bt_context_t *context, jl_task_t *ct); JL_DLLEXPORT void jl_raise_debugger(void) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_gdblookup(void* ip) JL_NOTSAFEPOINT; diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index e676eabbddad3..1d8ed0e19b04b 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -131,6 +131,38 @@ JL_DLLEXPORT void jl_push_newly_inferred(jl_value_t* ci) JL_UNLOCK(&newly_inferred_mutex); } + +static jl_array_t *inference_entrance_backtraces JL_GLOBALLY_ROOTED /*FIXME*/ = NULL; +// Mutex for inference_entrance_backtraces +jl_mutex_t inference_entrance_backtraces_mutex; + +// Register array of inference entrance backtraces +JL_DLLEXPORT void jl_set_inference_entrance_backtraces(jl_value_t* _inference_entrance_backtraces) +{ + assert(_inference_entrance_backtraces == NULL || _inference_entrance_backtraces == jl_nothing || jl_is_array(_inference_entrance_backtraces)); + if (_inference_entrance_backtraces == jl_nothing) + _inference_entrance_backtraces = NULL; + JL_LOCK(&inference_entrance_backtraces_mutex); + inference_entrance_backtraces = (jl_array_t*) _inference_entrance_backtraces; + JL_UNLOCK(&inference_entrance_backtraces_mutex); +} + + +JL_DLLEXPORT void jl_push_inference_entrance_backtraces(jl_value_t* ci) +{ + JL_LOCK(&inference_entrance_backtraces_mutex); + if (inference_entrance_backtraces == NULL) { + JL_UNLOCK(&inference_entrance_backtraces_mutex); + return; + } + jl_value_t* backtrace = jl_backtrace_from_here(0, 1); + size_t end = jl_array_nrows(inference_entrance_backtraces); + jl_array_grow_end(inference_entrance_backtraces, 2); + jl_array_ptr_set(inference_entrance_backtraces, end, ci); + jl_array_ptr_set(inference_entrance_backtraces, end + 1, backtrace); + JL_UNLOCK(&inference_entrance_backtraces_mutex); +} + // compute whether a type references something internal to worklist // and thus could not have existed before deserialize // and thus does not need delayed unique-ing diff --git a/test/stacktraces.jl b/test/stacktraces.jl index 3df0998fe88f6..169fc7c69f6c8 100644 --- a/test/stacktraces.jl +++ b/test/stacktraces.jl @@ -262,3 +262,39 @@ end @testset "Base.StackTraces docstrings" begin @test isempty(Docs.undocumented_names(StackTraces)) end + + +@testset "Dispatch backtraces" begin + # Check that it's possible to capture a backtrace upon entrance to inference + # This test ensures that SnoopCompile will continue working + # See in particular SnoopCompile/SnoopCompileCore/src/snoop_inference.jl + # and the "diagnostics" devdoc. + @noinline callee(x::Int) = sin(x) + caller(x) = invokelatest(callee, x) + + @test sin(0) == 0 # force compilation of sin(::Int) + dispatch_backtraces = [] + ccall(:jl_set_inference_entrance_backtraces, Cvoid, (Any,), dispatch_backtraces) + caller(3) + ccall(:jl_set_inference_entrance_backtraces, Cvoid, (Any,), nothing) + ln = @__LINE__() - 2 + fl = Symbol(@__FILE__()) + @test length(dispatch_backtraces) == 4 # 2 ci-backtrace pairs, stored as 4 separate elements + mcallee, mcaller = only(methods(callee)), only(methods(caller)) + # Extract pairs from the flattened array format: ci at odd indices, backtrace at even indices + pairs = [(dispatch_backtraces[i], dispatch_backtraces[i+1]) for i in 1:2:length(dispatch_backtraces)] + @test any(pairs) do (ci, trace) + # trace is a SimpleVector from jl_backtrace_from_here, need to reformat before stacktrace + bt = Base._reformat_bt(trace[1], trace[2]) + ci.def.def === mcallee && any(stacktrace(bt)) do sf + sf.file == fl && sf.line == ln + end + end + @test any(pairs) do (ci, trace) + # trace is a SimpleVector from jl_backtrace_from_here, need to reformat before stacktrace + bt = Base._reformat_bt(trace[1], trace[2]) + ci.def.def === mcaller && any(stacktrace(bt)) do sf + sf.file == fl && sf.line == ln + end + end +end From 843592e415641238b3b2a76adf3643956d32396d Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Thu, 21 Aug 2025 16:04:51 -0600 Subject: [PATCH 11/23] Fix nospecializing Functions in `Union{Nothing,Function}` params (#59327) Fixes https://github.com/JuliaLang/julia/issues/59326. Change the logic that decides not to specialize a function parameter based on whether or not the supplied argument is a Function, and that function is not used, so that it will still work if the SpecType is a Union{Function,Nothing} or any other union that contains a Function. The logic is changed from a hardcoded rule of `type_i == Function || type_i == Any || type_i == Base.Callable` to `type_i >: Function`. This covers all of the above cases, but also includes custom `Union{Function, T}` such as `Union{Function, Nothing}`. --------- Co-authored-by: Nick Robinson Co-authored-by: Jameson Nash (cherry picked from commit 9612115e684170841b806c2b8f6690f7c30d22e0) --- src/gf.c | 23 ++++++--------------- test/core.jl | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 17 deletions(-) diff --git a/src/gf.c b/src/gf.c index 37d78cdaa2cc3..741f9009b6961 100644 --- a/src/gf.c +++ b/src/gf.c @@ -1217,14 +1217,9 @@ static void jl_compilation_sig( int notcalled_func = (i_arg > 0 && i_arg <= 8 && !(definition->called & (1 << (i_arg - 1))) && !jl_has_free_typevars(decl_i) && jl_subtype(elt, (jl_value_t*)jl_function_type)); - if (notcalled_func && (type_i == (jl_value_t*)jl_any_type || - type_i == (jl_value_t*)jl_function_type || - (jl_is_uniontype(type_i) && // Base.Callable - ((((jl_uniontype_t*)type_i)->a == (jl_value_t*)jl_function_type && - ((jl_uniontype_t*)type_i)->b == (jl_value_t*)jl_type_type) || - (((jl_uniontype_t*)type_i)->b == (jl_value_t*)jl_function_type && - ((jl_uniontype_t*)type_i)->a == (jl_value_t*)jl_type_type))))) { - // and attempt to despecialize types marked Function, Callable, or Any + if (notcalled_func && (jl_subtype((jl_value_t*)jl_function_type, type_i))) { + // and attempt to despecialize types marked as a supertype of Function (i.e. + // Function, Callable, Any, or a Union{Function, T}) // when called with a subtype of Function but is not called if (!*newparams) *newparams = jl_svec_copy(tt->parameters); jl_svecset(*newparams, i, (jl_value_t*)jl_function_type); @@ -1450,15 +1445,9 @@ JL_DLLEXPORT int jl_isa_compileable_sig( int notcalled_func = (i_arg > 0 && i_arg <= 8 && !(definition->called & (1 << (i_arg - 1))) && !jl_has_free_typevars(decl_i) && jl_subtype(elt, (jl_value_t*)jl_function_type)); - if (notcalled_func && (type_i == (jl_value_t*)jl_any_type || - type_i == (jl_value_t*)jl_function_type || - (jl_is_uniontype(type_i) && // Base.Callable - ((((jl_uniontype_t*)type_i)->a == (jl_value_t*)jl_function_type && - ((jl_uniontype_t*)type_i)->b == (jl_value_t*)jl_type_type) || - (((jl_uniontype_t*)type_i)->b == (jl_value_t*)jl_function_type && - ((jl_uniontype_t*)type_i)->a == (jl_value_t*)jl_type_type))))) { - // and attempt to despecialize types marked Function, Callable, or Any - // when called with a subtype of Function but is not called + if (notcalled_func && jl_subtype((jl_value_t*)jl_function_type, type_i)) { + // and attempt to despecialize types marked as a supertype of Function (i.e. + // Function, Callable, Any, or a Union{Function, T}) if (elt == (jl_value_t*)jl_function_type) continue; JL_GC_POP(); diff --git a/test/core.jl b/test/core.jl index a7746de08a710..db0e0905f12a3 100644 --- a/test/core.jl +++ b/test/core.jl @@ -243,6 +243,62 @@ k11840(::Type{Union{Tuple{Int32}, Tuple{Int64}}}) = '2' @test k11840(Tuple{Union{Int32, Int64}}) == '2' @test k11840(Union{Tuple{Int32}, Tuple{Int64}}) == '2' +# issue #59327 +@noinline f59327(f, x) = Any[f, x] +g59327(x) = f59327(+, Any[x][1]) +g59327(1) +@test any( + mi->mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(f59327), Function, Int}, + methods(f59327)[1].specializations) + +@noinline h59327(f::Union{Function, Nothing}, x) = Any[f, x] +i59327(x) = h59327(+, Any[x][1]) +i59327(1) +@test any( + mi->mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(h59327), Function, Int}, + methods(h59327)[1].specializations) + +@noinline j59327(f::Function, x) = Any[f, x] +k59327(x) = j59327(+, Any[x][1]) +k59327(1) +@test any( + mi->mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(j59327), Function, Int}, + methods(j59327)[1].specializations +) + +@noinline l59327(f::Base.Callable, x) = Any[f, x] +m59327(x) = l59327(+, Any[x][1]) +m59327(1) +@test any( + mi->mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(l59327), Function, Int}, + methods(l59327)[1].specializations +) + +# _do_ specialize if the signature has a `where` +@noinline n59327(f::F, x) where F = Any[f, x] +o59327(x) = n59327(+, Any[x][1]) +o59327(1) +@test !any( + mi->mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(n59327), Function, Int}, + methods(n59327)[1].specializations +) +@test any( + mi->mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(n59327), typeof(+), Int}, + methods(n59327)[1].specializations +) + +# _do_ specialize if the signature is specific +@noinline n59327(f::typeof(+), x) = Any[f, x] +o59327(x) = n59327(+, Any[x][1]) +o59327(1) +@test !any( + mi->mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(n59327), Function, Int}, + methods(n59327)[1].specializations +) +@test any( + mi->mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(n59327), typeof(+), Int}, + methods(n59327)[1].specializations +) # issue #20511 f20511(x::DataType) = 0 From 7ea72028e87ab9d55b0d19a3887fb36584619ecc Mon Sep 17 00:00:00 2001 From: Martin Kunz Date: Fri, 22 Aug 2025 11:35:50 +0200 Subject: [PATCH 12/23] docs(compat): Add missing compat admonition to IdSet docstring (#59290) (cherry picked from commit 096011caea80f0407725bb4bd0e614c2614d2a23) --- base/idset.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/base/idset.jl b/base/idset.jl index 95c9bf784f557..2d71898ab1c3a 100644 --- a/base/idset.jl +++ b/base/idset.jl @@ -10,6 +10,9 @@ IdSet{T}() constructs a set (see [`Set`](@ref)) using In the example below, the values are all `isequal` so they get overwritten in the ordinary `Set`. The `IdSet` compares by `===` and so preserves the 3 different values. +!!! compat "Julia 1.11" + Exported in Julia 1.11 and later. + # Examples ```jldoctest; filter = r"\\n\\s*(1|1\\.0|true)" julia> Set(Any[true, 1, 1.0]) From 81ab4fcdbbcfb8408ec39cb9614d5abac91a986a Mon Sep 17 00:00:00 2001 From: Sam Schweigel Date: Fri, 22 Aug 2025 14:57:45 -0700 Subject: [PATCH 13/23] aotcompile: destroy LLVM context after serializing combined module (#59329) We already save some memory here by deleting the `jl_native_code_desc_t` after we're done serializing the combined module, but some data in the module's `LLVM::Context` lives on until the end of the scope in `jl_dump_native_impl`. Once we're done with the module, move the lock and `ThreadSafeContext` so the reference count drops to zero. A crude measurement shows that when compiling the Base sysimage, about 3 GiB is in use. Deleting the `jl_native_code_desc_t` (as before) saves about 600 MiB, and cleaning up the context saves an additional ~500 MiB. (cherry picked from commit ceeb661e2eaa14d3e2e174095c5747f7a7124725) --- src/aotcompile.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 4393a99c73380..c0a0bd2d14460 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -2169,9 +2169,14 @@ void jl_dump_native_impl(void *native_code, auto lock = TSCtx.getLock(); auto dataM = data->M.getModuleUnlocked(); - // Delete data when add_output thinks it's done with it - // Saves memory for use when multithreading - data_outputs = compile(*dataM, "text", threads, [data](Module &) { delete data; }); + data_outputs = compile(*dataM, "text", threads, [data, &lock, &TSCtx](Module &) { + // Delete data when add_output thinks it's done with it + // Saves memory for use when multithreading + auto lock2 = std::move(lock); + delete data; + // Drop last reference to shared LLVM::Context + auto TSCtx2 = std::move(TSCtx); + }); } if (params->emit_metadata) { From e7424c00a4c49702ad7bbd74afa63b938f7bbbc6 Mon Sep 17 00:00:00 2001 From: James Wrigley Date: Sun, 24 Aug 2025 08:54:18 +0200 Subject: [PATCH 14/23] Update Artifacts precompile statement (#59371) The `@__artifact_str` macro was updated in https://github.com/JuliaLang/julia/pull/55707. ```julia-repl # Before julia> @time import ZeroMQ_jll 0.119653 seconds (313.44 k allocations: 16.855 MiB, 79.48% compilation time) # After julia> @time import ZeroMQ_jll 0.024658 seconds (22.61 k allocations: 1.830 MiB) ``` (cherry picked from commit d28a587c89291cf2c969ac7495e38e8e6fe622e1) --- stdlib/Artifacts/src/Artifacts.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stdlib/Artifacts/src/Artifacts.jl b/stdlib/Artifacts/src/Artifacts.jl index 3b20e5feb3da3..4af706606d326 100644 --- a/stdlib/Artifacts/src/Artifacts.jl +++ b/stdlib/Artifacts/src/Artifacts.jl @@ -766,6 +766,5 @@ precompile(NamedTuple{(:pkg_uuid,)}, (Tuple{Base.UUID},)) precompile(Core.kwfunc(load_artifacts_toml), (NamedTuple{(:pkg_uuid,), Tuple{Base.UUID}}, typeof(load_artifacts_toml), String)) precompile(parse_mapping, (String, String, String)) precompile(parse_mapping, (Dict{String, Any}, String, String)) -precompile(Tuple{typeof(Artifacts._artifact_str), Module, String, Base.SubString{String}, String, Base.Dict{String, Any}, Base.SHA1, Base.BinaryPlatforms.Platform, Any}) - +precompile(Tuple{typeof(Artifacts.__artifact_str), Module, String, Base.SubString{String}, String, Base.Dict{String, Any}, Base.SHA1, Base.BinaryPlatforms.Platform, Base.Val{Artifacts}}) end # module Artifacts From dd5c59231c6264ee7db256463ca69fccb16cc1bf Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Mon, 25 Aug 2025 09:34:23 -0600 Subject: [PATCH 15/23] Fixup measurement for --trace-compile-timing w/ nested compilations. (#59363) Use a separate inference_start and compilation_start, where compilation_start does not do anything special for reentrancy. Here is an example which has a quick-to-compile nested dynamic dispatch, but that nested function runs for a long time: ```julia ./julia --startup=no --trace-compile=stderr --trace-compile-timing -e ' Base.@assume_effects :foldable function nested1(x) sum(collect(x for _ in 1:1000_000_000)) end f1(x) = nested1(sizeof(x)) + x f1(2)' #= 12.7 ms =# precompile(Tuple{typeof(Main.nested1), Int64}) #= 3809.3 ms =# precompile(Tuple{typeof(Main.f1), Int64}) ``` This fixes a small issue introduced here: https://github.com/JuliaLang/julia/pull/59220/files#r2292021838 (cherry picked from commit be59100b5dae4e08c3eda3bcdd15e5fb878b824e) --- src/gf.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/gf.c b/src/gf.c index 741f9009b6961..06bf3b62deda0 100644 --- a/src/gf.c +++ b/src/gf.c @@ -3483,7 +3483,8 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t // Ok, compilation is enabled. We'll need to try to compile something (probably). // Everything from here on is considered (user facing) compile time - uint64_t start = jl_typeinf_timing_begin(); + uint64_t compilation_start = jl_hrtime(); + uint64_t inference_start = jl_typeinf_timing_begin(); // Special-handling for reentrancy // Is a recompile if there is cached code, and it was compiled (not only inferred) before int is_recompile = 0; @@ -3510,14 +3511,14 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t if (codeinst) { if (jl_is_compiled_codeinst(codeinst)) { - jl_typeinf_timing_end(start, is_recompile); + jl_typeinf_timing_end(inference_start, is_recompile); // Already compiled - e.g. constabi, or compiled by a different thread while we were waiting. return codeinst; } JL_GC_PUSH1(&codeinst); int did_compile = jl_compile_codeinst(codeinst); - double compile_time = jl_hrtime() - start; + double compile_time = jl_hrtime() - compilation_start; if (jl_atomic_load_relaxed(&codeinst->invoke) == NULL) { // Something went wrong. Bail to the fallback path. @@ -3547,7 +3548,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t if (ucache_invoke != jl_fptr_sparam && ucache_invoke != jl_fptr_interpret_call) { // only these care about the exact specTypes, otherwise we can use it directly - jl_typeinf_timing_end(start, is_recompile); + jl_typeinf_timing_end(inference_start, is_recompile); return ucache; } uint8_t specsigflags; @@ -3565,7 +3566,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t jl_mi_cache_insert(mi, codeinst); } jl_atomic_store_relaxed(&codeinst->precompile, 1); - jl_typeinf_timing_end(start, is_recompile); + jl_typeinf_timing_end(inference_start, is_recompile); return codeinst; } From ddc56a09f1a27e4265d378fc694f3e31ada3a408 Mon Sep 17 00:00:00 2001 From: Neven Sajko <4944410+nsajko@users.noreply.github.com> Date: Tue, 26 Aug 2025 14:00:46 +0200 Subject: [PATCH 16/23] work around some closure capture boxing inference issues in loading (#59367) The only method of the `__require_prelocked` function in `Base` gets compiled with bad inference for two variables, `path` and `reasons`, which get pessimistically boxed (and inferred as `Any`), even though both of them are only assigned to once across both the method and the closure within (neither is assigned to within the closure). My guess for what causes this would be either of these, or the combination: * (mis)use of GOTO * `try`-`catch` The least demanding way to work around the issue is adding a `let` around the closure, as advised in the Performance tips. That is what this change does. This change should fix several bad inference results within method instances such as `__require_prelocked(::PkgId, ::Nothing)` and `__require_prelocked(::PkgId, ::String)`. Consequently, the sysimage should become less vulnerable to invalidation happening when loading certain packages. (cherry picked from commit 547f85849b30f8ef3b5fce84c6c8a7f09e328baf) --- base/loading.jl | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/base/loading.jl b/base/loading.jl index b8962eeaa4d1c..c69f28cdc5a02 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -2634,21 +2634,23 @@ function __require_prelocked(pkg::PkgId, env) @goto load_from_cache end # spawn off a new incremental pre-compile task for recursive `require` calls - loaded = maybe_cachefile_lock(pkg, path) do - # double-check the search now that we have lock - m = _require_search_from_serialized(pkg, path, UInt128(0), true) - m isa Module && return m - triggers = get(EXT_PRIMED, pkg, nothing) - loadable_exts = nothing - if triggers !== nothing # extension - loadable_exts = PkgId[] - for (ext′, triggers′) in EXT_PRIMED - if triggers′ ⊊ triggers - push!(loadable_exts, ext′) + loaded = let path = path, reasons = reasons + maybe_cachefile_lock(pkg, path) do + # double-check the search now that we have lock + m = _require_search_from_serialized(pkg, path, UInt128(0), true) + m isa Module && return m + triggers = get(EXT_PRIMED, pkg, nothing) + loadable_exts = nothing + if triggers !== nothing # extension + loadable_exts = PkgId[] + for (ext′, triggers′) in EXT_PRIMED + if triggers′ ⊊ triggers + push!(loadable_exts, ext′) + end end end + return compilecache(pkg, path; reasons, loadable_exts) end - return compilecache(pkg, path; reasons, loadable_exts) end loaded isa Module && return loaded if isnothing(loaded) # maybe_cachefile_lock returns nothing if it had to wait for another process From 2841be907c48793b5e48e7f2d8f2b4e5d437e932 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 26 Aug 2025 10:53:48 -0400 Subject: [PATCH 17/23] atomics: correctly implement padding write of 11 byte atomics with 4 byte pointer (#59395) On 32 bit machines, for an atomic of size 9 to 11 bytes, the result fits in the 16 byte pool, but only with a maximum write of 12 bytes (there is 1 byte reserved for the `success` plus 4 for the type tag, leaving 11 bytes for the data). This was accidentally doing a 16 byte write instead, which could smash the type tag field (usually will NULL) of the next object. Not sure how to test, since just noticed this while reading the code. (cherry picked from commit bbd491a52fd82c78aa55c11c7cf290e6f9a2d93c) --- src/datatype.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/datatype.c b/src/datatype.c index f6cdf21c81afb..5c771ed2a003a 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -1108,6 +1108,10 @@ static inline jl_uint128_t zext_read128(const jl_value_t *x, size_t nb) JL_NOTSA memcpy(&y, x, nb); return y; } +static void assign_uint128(jl_value_t *v, jl_uint128_t x, size_t nb) JL_NOTSAFEPOINT +{ + memcpy(v, &x, nb); +} #endif JL_DLLEXPORT jl_value_t *jl_new_bits(jl_value_t *dt, const void *data) @@ -1173,6 +1177,8 @@ JL_DLLEXPORT jl_value_t *jl_atomic_new_bits(jl_value_t *dt, const char *data) *(uint64_t*)v = jl_atomic_load((_Atomic(uint64_t)*)data); #endif #if MAX_POINTERATOMIC_SIZE >= 16 + else if (nb <= 12) + assign_uint128(v, jl_atomic_load((_Atomic(jl_uint128_t)*)data), 12); else if (nb <= 16) *(jl_uint128_t*)v = jl_atomic_load((_Atomic(jl_uint128_t)*)data); #endif @@ -1239,6 +1245,8 @@ JL_DLLEXPORT jl_value_t *jl_atomic_swap_bits(jl_value_t *dt, char *dst, const jl *(uint64_t*)v = jl_atomic_exchange((_Atomic(uint64_t)*)dst, zext_read64(src, nb)); #endif #if MAX_POINTERATOMIC_SIZE >= 16 + else if (nb <= 12) + assign_uint128(v, jl_atomic_exchange((_Atomic(jl_uint128_t)*)dst, zext_read128(src, nb)), 12); else if (nb <= 16) *(jl_uint128_t*)v = jl_atomic_exchange((_Atomic(jl_uint128_t)*)dst, zext_read128(src, nb)); #endif @@ -1288,7 +1296,7 @@ JL_DLLEXPORT int jl_atomic_bool_cmpswap_bits(char *dst, const jl_value_t *expect return success; } -JL_DLLEXPORT int jl_atomic_cmpswap_bits(jl_datatype_t *dt, jl_value_t *y /* pre-allocated output */, char *dst, const jl_value_t *expected, const jl_value_t *src, int nb) +JL_DLLEXPORT int jl_atomic_cmpswap_bits(jl_datatype_t *dt, jl_value_t *y /* NEW pre-allocated output */, char *dst, const jl_value_t *expected, const jl_value_t *src, int nb) { // dst must have the required alignment for an atomic of the given size // n.b.: this does not spuriously fail if there are padding bits @@ -1359,18 +1367,19 @@ JL_DLLEXPORT int jl_atomic_cmpswap_bits(jl_datatype_t *dt, jl_value_t *y /* pre- #endif #if MAX_POINTERATOMIC_SIZE >= 16 else if (nb <= 16) { - jl_uint128_t *y128 = (jl_uint128_t*)y; if (dt == et) { - *y128 = zext_read128(expected, nb); + jl_uint128_t y128 = zext_read128(expected, nb); jl_uint128_t z128 = zext_read128(src, nb); while (1) { - success = jl_atomic_cmpswap((_Atomic(jl_uint128_t)*)dst, y128, z128); - if (success || (dt->layout->flags.isbitsegal && !dt->layout->flags.haspadding) || !jl_egal__bits(y, expected, dt)) + success = jl_atomic_cmpswap((_Atomic(jl_uint128_t)*)dst, &y128, z128); + assign_uint128(y, y128, nb); + if (success || (dt->layout->flags.isbitsegal && !dt->layout->flags.haspadding) || !jl_egal__bits(y, expected, dt)) { break; + } } } else { - *y128 = jl_atomic_load((_Atomic(jl_uint128_t)*)dst); + assign_uint128(y, jl_atomic_load((_Atomic(jl_uint128_t)*)dst), nb); success = 0; } } From 2df5f57de0a548650d8a3076c6bae4190e965eeb Mon Sep 17 00:00:00 2001 From: Lionel Zoubritzky Date: Tue, 26 Aug 2025 23:15:19 +0200 Subject: [PATCH 18/23] Remove obsolete paragraph on struct redefinition from FAQ (#59399) The FAQ for Julia v1.12 and master still contains a paragraph that explains how to work around the impossibility to redefine a type in a REPL session. This paragraph is now obsolete thanks to #57253 so I propose to simply remove it. (cherry picked from commit 0c1fab4fd2a3943801bab055d45bba2a40fc1080) --- doc/src/manual/faq.md | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/doc/src/manual/faq.md b/doc/src/manual/faq.md index 188b8b7f79f3a..385451af91b13 100644 --- a/doc/src/manual/faq.md +++ b/doc/src/manual/faq.md @@ -74,35 +74,6 @@ If memory usage is your concern, you can always replace objects with ones that c with `A = nothing`. The memory will be released the next time the garbage collector runs; you can force this to happen with [`GC.gc()`](@ref Base.GC.gc). Moreover, an attempt to use `A` will likely result in an error, because most methods are not defined on type `Nothing`. -### How can I modify the declaration of a type in my session? - -Perhaps you've defined a type and then realize you need to add a new field. If you try this at -the REPL, you get the error: - -``` -ERROR: invalid redefinition of constant MyType -``` - -Types in module `Main` cannot be redefined. - -While this can be inconvenient when you are developing new code, there's an excellent workaround. - Modules can be replaced by redefining them, and so if you wrap all your new code inside a module -you can redefine types and constants. You can't import the type names into `Main` and then expect -to be able to redefine them there, but you can use the module name to resolve the scope. In other -words, while developing you might use a workflow something like this: - -```julia -include("mynewcode.jl") # this defines a module MyModule -obj1 = MyModule.ObjConstructor(a, b) -obj2 = MyModule.somefunction(obj1) -# Got an error. Change something in "mynewcode.jl" -include("mynewcode.jl") # reload the module -obj1 = MyModule.ObjConstructor(a, b) # old objects are no longer valid, must reconstruct -obj2 = MyModule.somefunction(obj1) # this time it worked! -obj3 = MyModule.someotherfunction(obj2, c) -... -``` - ## [Scripting](@id man-scripting) ### How do I check if the current file is being run as the main script? From b4204697d3b9fd3aa763f9ac38a6cd0729bbef67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gunnar=20Farneb=C3=A4ck?= Date: Sat, 30 Aug 2025 23:18:35 +0200 Subject: [PATCH 19/23] Correctly set the variant bits of uuid1 (#59428) (cherry picked from commit a7764454679740ec2098904e715172a7206e0a6b) --- stdlib/UUIDs/src/UUIDs.jl | 4 ++-- stdlib/UUIDs/test/runtests.jl | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/stdlib/UUIDs/src/UUIDs.jl b/stdlib/UUIDs/src/UUIDs.jl index e29cf3ff7597e..a2fd13a1c7cd1 100644 --- a/stdlib/UUIDs/src/UUIDs.jl +++ b/stdlib/UUIDs/src/UUIDs.jl @@ -74,8 +74,8 @@ function _build_uuid1(rng::AbstractRNG, timestamp::UInt64) # mask off clock sequence and node u &= 0x00000000000000003fffffffffffffff - # set the unicast/multicast bit and version - u |= 0x00000000000010000000010000000000 + # set the version, variant, and unicast/multicast bit + u |= 0x00000000000010008000010000000000 ts_low = timestamp & typemax(UInt32) ts_mid = (timestamp >> 32) & typemax(UInt16) diff --git a/stdlib/UUIDs/test/runtests.jl b/stdlib/UUIDs/test/runtests.jl index c6da441076ea8..27bcad1f20dc5 100644 --- a/stdlib/UUIDs/test/runtests.jl +++ b/stdlib/UUIDs/test/runtests.jl @@ -42,6 +42,15 @@ u7 = uuid7() @test uuid_version(u7) == 7 end +@testset "Extraction of variant bits" begin + # RFC 4122, section 4.1.1 + uuid_variant(u::UUID) = Int((u.value >> 62) & 0x3) + @test uuid_variant(u1) == 2 + @test uuid_variant(u4) == 2 + @test uuid_variant(u5) == 2 + @test uuid_variant(u7) == 2 +end + @testset "Parsing from string" begin @test u1 == UUID(string(u1)) == UUID(GenericString(string(u1))) @test u4 == UUID(string(u4)) == UUID(GenericString(string(u4))) From 3a9511e3f78e86e33cd4d01e8dd42815c53e816f Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Thu, 21 Aug 2025 08:26:23 +0100 Subject: [PATCH 20/23] Add a long running warn to Base.runtests (#59288) (cherry picked from commit 6a783956c1febc505e194fa23f4d89efea48dc53) --- test/runtests.jl | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 1872c888333da..a15816390986a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -15,6 +15,9 @@ include("buildkitetestjson.jl") using .BuildkiteTestJSON +const longrunning_delay = parse(Int, get(ENV, "JULIA_TEST_LONGRUNNING_DELAY", "45")) * 60 # minutes +const longrunning_interval = parse(Int, get(ENV, "JULIA_TEST_LONGRUNNING_INTERVAL", "15")) * 60 # minutes + (; tests, net_on, exit_on_error, use_revise, seed) = choosetests(ARGS) tests = unique(tests) @@ -175,10 +178,10 @@ cd(@__DIR__) do at = lpad("($wrkr)", name_align - textwidth(name) + 1, " ") lock(print_lock) try - printstyled(name, at, " |", " "^elapsed_align, - "started at $(now())", + printstyled(name, at, " |", " "^elapsed_align, color=:white) + printstyled("started at $(now())", (pid > 0 ? " on pid $pid" : ""), - "\n", color=:white) + "\n", color=:light_black) finally unlock(print_lock) end @@ -215,6 +218,10 @@ cd(@__DIR__) do # Monitor stdin and kill this task on ^C # but don't do this on Windows, because it may deadlock in the kernel running_tests = Dict{String, DateTime}() + + # Track timeout timers for each test + test_timers = Dict{String, Timer}() + if !Sys.iswindows() && isa(stdin, Base.TTY) t = current_task() stdin_monitor = @async begin @@ -249,6 +256,33 @@ cd(@__DIR__) do test = popfirst!(tests) running_tests[test] = now() wrkr = p + + # Create a timer for this test to report long-running status + test_timers[test] = Timer(longrunning_delay, interval=longrunning_interval) do timer + if haskey(running_tests, test) # Check test is still running + start_time = running_tests[test] + elapsed = now() - start_time + elapsed_minutes = elapsed.value ÷ (1000 * 60) + + elapsed_str = if elapsed_minutes >= 60 + hours, mins = divrem(elapsed_minutes, 60) + "$(hours)h $(mins)m" + else + "$(elapsed_minutes)m" + end + + @lock print_lock begin + print(test) + print(lpad("($(wrkr))", name_align - textwidth(test) + 1, " "), " | ") + # Calculate total width of data columns: "Time (s) | GC (s) | GC % | Alloc (MB) | RSS (MB)" + # This is: elapsed_align + 3 + gc_align + 3 + percent_align + 3 + alloc_align + 3 + rss_align + data_width = elapsed_align + gc_align + percent_align + alloc_align + rss_align + 12 # 12 = 4 * " | " + message = "has been running for $(elapsed_str)" + centered_message = lpad(rpad(message, (data_width + textwidth(message)) ÷ 2), data_width) + printstyled(centered_message, "\n", color=:light_black) + end + end + end before = time() resp, duration = try r = remotecall_fetch(@Base.world(runtests, ∞), wrkr, test, test_path(test); seed=seed) @@ -258,6 +292,10 @@ cd(@__DIR__) do Any[CapturedException(e, catch_backtrace())], time() - before end delete!(running_tests, test) + if haskey(test_timers, test) + close(test_timers[test]) + delete!(test_timers, test) + end push!(results, (test, resp, duration)) if length(resp) == 1 print_testworker_errored(test, wrkr, exit_on_error ? nothing : resp[1]) @@ -342,6 +380,9 @@ cd(@__DIR__) do if @isdefined stdin_monitor schedule(stdin_monitor, InterruptException(); error=true) end + if @isdefined test_timers + foreach(close, values(test_timers)) + end end #= From eef989cbd4ed990a1cb681d94371a67979f1cbc4 Mon Sep 17 00:00:00 2001 From: Zentrik Date: Tue, 29 Apr 2025 16:50:29 +0100 Subject: [PATCH 21/23] Rename `_aligned_msize` to prevent conflict with mingw64 defintion (#58238) `_aligned_msize` is now declared in mingw64's crt (https://github.com/mingw-w64/mingw-w64/commit/b40e24afb12524ab97ad27d21f9b35f9f4bab678) as `_CRTIMP size_t __cdecl _aligned_msize(void *_Memory,size_t _Alignment,size_t _Offset);`. Renamed our version to prevent the conflict (cherry picked from commit 2270fcdcc655c8fa7aa9472069434389f895b147) --- src/gc-common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gc-common.c b/src/gc-common.c index c07b707b17709..87ddb68abc704 100644 --- a/src/gc-common.c +++ b/src/gc-common.c @@ -126,7 +126,7 @@ JL_DLLEXPORT void jl_gc_set_cb_notify_gc_pressure(jl_gc_cb_notify_gc_pressure_t // but with several fixes to improve the correctness of the computation and remove unnecessary parameters #define SAVED_PTR(x) ((void *)((DWORD_PTR)((char *)x - sizeof(void *)) & \ ~(sizeof(void *) - 1))) -static size_t _aligned_msize(void *p) +static size_t _jl_aligned_msize(void *p) { void *alloc_ptr = *(void**)SAVED_PTR(p); return _msize(alloc_ptr) - ((char*)p - (char*)alloc_ptr); @@ -138,7 +138,7 @@ size_t memory_block_usable_size(void *p, int isaligned) JL_NOTSAFEPOINT { #if defined(_OS_WINDOWS_) if (isaligned) - return _aligned_msize(p); + return _jl_aligned_msize(p); else return _msize(p); #elif defined(_OS_DARWIN_) From 552d97c0a841f700dab0cc1c295800d4b0f6b0f6 Mon Sep 17 00:00:00 2001 From: FX Coudert Date: Sun, 17 Aug 2025 17:51:20 +0200 Subject: [PATCH 22/23] openlibm 0.8.7 (#59312) Released 3 June 2025 https://github.com/JuliaMath/openlibm/releases/tag/v0.8.7 (cherry picked from commit 61d04b308569ecb8a47de781f3d25987cedcc7e4) --- deps/checksums/openlibm | 76 ++++++++++++++++---------------- deps/openlibm.version | 6 +-- stdlib/Manifest.toml | 2 +- stdlib/OpenLibm_jll/Project.toml | 2 +- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/deps/checksums/openlibm b/deps/checksums/openlibm index cad61fd42cf94..fc20184ac85da 100644 --- a/deps/checksums/openlibm +++ b/deps/checksums/openlibm @@ -1,38 +1,38 @@ -OpenLibm.v0.8.5+0.aarch64-apple-darwin.tar.gz/md5/5fcbd746e90712e396e76dc4e76724d0 -OpenLibm.v0.8.5+0.aarch64-apple-darwin.tar.gz/sha512/f4ac2bc38bdc723384b67119daa2974fb43da34b2e45cea2029ea48f92c84c4cad6dfb43521b09a1e89ddf8c5b8cc22a38fa4b78ba39ac7524fd6bd1ba897aa9 -OpenLibm.v0.8.5+0.aarch64-linux-gnu.tar.gz/md5/4d1b4cd566805b5179c5ecdd060da473 -OpenLibm.v0.8.5+0.aarch64-linux-gnu.tar.gz/sha512/a9fe1a3d2e3898c017eb8615b2f3dbb514995ff041ac964c931c99c60d8cfe4eab7563a9cd65058f42f83c812f33d998573a7c5cc56a2e3960a4657e459ed321 -OpenLibm.v0.8.5+0.aarch64-linux-musl.tar.gz/md5/413be59af62b3ce0ebafeca093e3179e -OpenLibm.v0.8.5+0.aarch64-linux-musl.tar.gz/sha512/7bd76373e047ba854066af61f1c56b2e3a4d28c266228d7b30f596eadbaec52b070548ae60d41840c425ad5d0829c6c0cdaf326f2f160ed7508877ab5ec1a4b1 -OpenLibm.v0.8.5+0.aarch64-unknown-freebsd.tar.gz/md5/80736f9022c695eb1198e0b591a8fa63 -OpenLibm.v0.8.5+0.aarch64-unknown-freebsd.tar.gz/sha512/c633644578265e7ccc259ceb0442457b8c09290b4861b66c86dd6be7b30c4e394e70728142798097d6fe3afcfb4d9d1bd7ef58513fe8eed5684a4fba51bf185a -OpenLibm.v0.8.5+0.armv6l-linux-gnueabihf.tar.gz/md5/8fe0900a318393a290907f016bc654c3 -OpenLibm.v0.8.5+0.armv6l-linux-gnueabihf.tar.gz/sha512/167100a2d46e68462ef9a66915ced881d6358f05337bd38f2f77176f41cfd5be37e3c5226dd5d7d59147bd3e1aa7fb0893c1c81e9516134d3ab663b5752c4969 -OpenLibm.v0.8.5+0.armv6l-linux-musleabihf.tar.gz/md5/e8566719387984604f19dc5f9354a783 -OpenLibm.v0.8.5+0.armv6l-linux-musleabihf.tar.gz/sha512/532dd2b764fa15f7a838fb14cccafd2d4fe8fa4a132ea8394479a719c7aee11442f1b8a18e5d4a26ca820fa696d9d2afc7f5ec63dd96fa3b6763cea72b7026c3 -OpenLibm.v0.8.5+0.armv7l-linux-gnueabihf.tar.gz/md5/8fe0900a318393a290907f016bc654c3 -OpenLibm.v0.8.5+0.armv7l-linux-gnueabihf.tar.gz/sha512/167100a2d46e68462ef9a66915ced881d6358f05337bd38f2f77176f41cfd5be37e3c5226dd5d7d59147bd3e1aa7fb0893c1c81e9516134d3ab663b5752c4969 -OpenLibm.v0.8.5+0.armv7l-linux-musleabihf.tar.gz/md5/e8566719387984604f19dc5f9354a783 -OpenLibm.v0.8.5+0.armv7l-linux-musleabihf.tar.gz/sha512/532dd2b764fa15f7a838fb14cccafd2d4fe8fa4a132ea8394479a719c7aee11442f1b8a18e5d4a26ca820fa696d9d2afc7f5ec63dd96fa3b6763cea72b7026c3 -OpenLibm.v0.8.5+0.i686-linux-gnu.tar.gz/md5/9580d34e69d6067427b9c33db631cfd3 -OpenLibm.v0.8.5+0.i686-linux-gnu.tar.gz/sha512/46934f82791f69ac5f5da0dab7dcc6e3e9a4577c3bb529e9c0519c38f140c7b54517c55ff3579cd4ed4df68f0863e006aa98e51873f1dab452ce9f853996429a -OpenLibm.v0.8.5+0.i686-linux-musl.tar.gz/md5/66bfc9611d04c5d609e7824cb076d24b -OpenLibm.v0.8.5+0.i686-linux-musl.tar.gz/sha512/1bda2395d44c22aba3d1aab2b08ae06f763d3755037d454aa73f8e8134289a1ab5d65862bbc5a17a7a6b9f2918eb87e926b21527ddc4471e2ea20d605ba14e2d -OpenLibm.v0.8.5+0.i686-w64-mingw32.tar.gz/md5/0e97311b2f08b57d79085635f01ccced -OpenLibm.v0.8.5+0.i686-w64-mingw32.tar.gz/sha512/ae061ea406c06969332af58ed6fdfce2825326d771d30274d90775a1709b0361b7ca1dc7e6b0b76b93e4dd7a81d1842510a2c835251ee0a0978d6c839d96070e -OpenLibm.v0.8.5+0.powerpc64le-linux-gnu.tar.gz/md5/8ecfff7db76eee29591a654871e88855 -OpenLibm.v0.8.5+0.powerpc64le-linux-gnu.tar.gz/sha512/af03993b162316dd581f6ba5d1c23bca4c26cb22356ab229f326c42e111acbdf7ef45c9ad05894fe2d68794a63670cf89888653f788192a38b9255ce4bc72e28 -OpenLibm.v0.8.5+0.riscv64-linux-gnu.tar.gz/md5/69e06de135940666791c984941e9c4ad -OpenLibm.v0.8.5+0.riscv64-linux-gnu.tar.gz/sha512/2ac84deb7eb80a6a6237eff6fe861fd2907b3c95d1a76366dea062f3f35228dbc67aa40bd982e646508b4ff7cb6ef029111e2c0325039e60679800d6c6886be5 -OpenLibm.v0.8.5+0.x86_64-apple-darwin.tar.gz/md5/bd671ab9fe01835cab3e42e7cfa790fb -OpenLibm.v0.8.5+0.x86_64-apple-darwin.tar.gz/sha512/8bf2e66df17effc1e8778453904ffc20127f785bf096873289e8fdd8b17069ca844faffbd9f7621b87a7cb0a0051037eb9402360f2a03cf8794fbac8f7719777 -OpenLibm.v0.8.5+0.x86_64-linux-gnu.tar.gz/md5/df7fab134fbce3b625e9a82376f23e79 -OpenLibm.v0.8.5+0.x86_64-linux-gnu.tar.gz/sha512/64d07434e0db79833f84a2225838456eb9532617d377a776b3a534a908b1673bc4f890903f95350e4045e05c29539d993a18ecadeb879761e279ec3947f74390 -OpenLibm.v0.8.5+0.x86_64-linux-musl.tar.gz/md5/ebef6bb7651d116b397e035f39adfb1b -OpenLibm.v0.8.5+0.x86_64-linux-musl.tar.gz/sha512/de9036073e5dba2721b4119ecbbd21a0c9f75b65aff9392b7e88e464da35b97135d62404477441d0dadd3a2f8d49f1082291b35bf4b626fb1096d36d401980bf -OpenLibm.v0.8.5+0.x86_64-unknown-freebsd.tar.gz/md5/1115497539f00a37af18aa6516d52268 -OpenLibm.v0.8.5+0.x86_64-unknown-freebsd.tar.gz/sha512/71a2c06d141b3671fd220f2d88d72e845848b6d2b08a7b3a6c4bb1d5cc27cc450e1e681647bb583e7ed6375d5a70748401e95e61dc95d7808f33a9aa06755337 -OpenLibm.v0.8.5+0.x86_64-w64-mingw32.tar.gz/md5/b6b5335f4c83f7ebf0f74cf753358f00 -OpenLibm.v0.8.5+0.x86_64-w64-mingw32.tar.gz/sha512/e8351ddda305b757f337bb7ea26c441968843b23861676f0bdd7bcf83bb3969af790d4112307d3204eb87fac044dda9be305f349700ebe9ba2bfe3d6df24fde8 -openlibm-db24332879c320606c37f77fea165e6ecb49153c.tar.gz/md5/2375dd448e77e59152442a4b33abda01 -openlibm-db24332879c320606c37f77fea165e6ecb49153c.tar.gz/sha512/36054e7051990d04913f054a0542e2e104273f61308e9a442c2dab3dd392d40c03f264fbeca93c4296218eed85dad71028989a225088254013d752f4407d57ef +OpenLibm.v0.8.7+0.aarch64-apple-darwin.tar.gz/md5/68dd4a8d49ed68ec464352220b006e66 +OpenLibm.v0.8.7+0.aarch64-apple-darwin.tar.gz/sha512/fc6f69c3477c99058a074784af2f19769de5fdfbecbcbec76ce1253de69788ff41304fe8677a50582f6628d3a50b889b0c56e19c0d7bb369c493d72810b2aef9 +OpenLibm.v0.8.7+0.aarch64-linux-gnu.tar.gz/md5/421644dba2a629013db582011b2e5f14 +OpenLibm.v0.8.7+0.aarch64-linux-gnu.tar.gz/sha512/429416fd411a06ab8576653fb5e07e6fc5e210a3d6939451a0d56593ae74c04c330ee7936fa10b6ca6c21748f697817e67506b98c49a11d39ae9a98a958bd6e8 +OpenLibm.v0.8.7+0.aarch64-linux-musl.tar.gz/md5/ee870854946972b6a2ff989cc1ca6c12 +OpenLibm.v0.8.7+0.aarch64-linux-musl.tar.gz/sha512/3f9c0514fdc296fa28562abfbc513bba442d48c3fdbe38622a0a9e16bfbfee39135247fcc4fd486abb629a86cc7afd342215baccb4db59d07a5a1fa2c8356549 +OpenLibm.v0.8.7+0.aarch64-unknown-freebsd.tar.gz/md5/02ca3e2e478e8d2eb3c7d24e1584ab6f +OpenLibm.v0.8.7+0.aarch64-unknown-freebsd.tar.gz/sha512/d1f44059270e5884bea9b7f14c15b251dff528002d3f1b61144b0d197891487b690917711ce648c298a7f8db6d8a2035b82acee3dfb2e9b18dc556a09c3b7128 +OpenLibm.v0.8.7+0.armv6l-linux-gnueabihf.tar.gz/md5/473f534041e403f04edb56846fcd8426 +OpenLibm.v0.8.7+0.armv6l-linux-gnueabihf.tar.gz/sha512/17e1c5cbd871091ac9e0057d334891bd795d690986b40ad903bfaaf89100604e5c0abb97e9675581d50893f85859e64f44139c9359149c629a9b06c20a8f46ae +OpenLibm.v0.8.7+0.armv6l-linux-musleabihf.tar.gz/md5/147b932a2d3b7b0636be22d849f33a5a +OpenLibm.v0.8.7+0.armv6l-linux-musleabihf.tar.gz/sha512/abd3ad5096ef280814dcff203aaa1cc39d53bc706913cc6aae92d33f7d0842760ccc44f6270f8023558347be8944b169d1d04e508f74f9158f6686484218ce2d +OpenLibm.v0.8.7+0.armv7l-linux-gnueabihf.tar.gz/md5/473f534041e403f04edb56846fcd8426 +OpenLibm.v0.8.7+0.armv7l-linux-gnueabihf.tar.gz/sha512/17e1c5cbd871091ac9e0057d334891bd795d690986b40ad903bfaaf89100604e5c0abb97e9675581d50893f85859e64f44139c9359149c629a9b06c20a8f46ae +OpenLibm.v0.8.7+0.armv7l-linux-musleabihf.tar.gz/md5/147b932a2d3b7b0636be22d849f33a5a +OpenLibm.v0.8.7+0.armv7l-linux-musleabihf.tar.gz/sha512/abd3ad5096ef280814dcff203aaa1cc39d53bc706913cc6aae92d33f7d0842760ccc44f6270f8023558347be8944b169d1d04e508f74f9158f6686484218ce2d +OpenLibm.v0.8.7+0.i686-linux-gnu.tar.gz/md5/7a7ceefec85b5054a1bc31b1fa93a7f8 +OpenLibm.v0.8.7+0.i686-linux-gnu.tar.gz/sha512/0117e9f8a2236757443fff50c530e2ffb7d713e1bf46997713a6987f8602ac8398748c3fc8c8ba0980d127408de0d2f0de5e53af2c1a911488723bfba531c0ba +OpenLibm.v0.8.7+0.i686-linux-musl.tar.gz/md5/39163327893bfa499c97d5dbfe892d10 +OpenLibm.v0.8.7+0.i686-linux-musl.tar.gz/sha512/68ac6dc53da509ef906ecab66070381de27b8d551d39c147982c7b5008ec21e6a3a32bbc2aa6cb4e5c3f883cae76fc1c96b5cdfca58b2dabbf05c734431bf594 +OpenLibm.v0.8.7+0.i686-w64-mingw32.tar.gz/md5/8bef2aa7010577a37b1d789980ecb97a +OpenLibm.v0.8.7+0.i686-w64-mingw32.tar.gz/sha512/6770de28fbf856fc21619f1aa0ac752d059a9bbb9668d56211cc4b33050835a41d2b6d5777c535d63c4083fb01d70b5874f63c65b93ea3ee15e3ac19372091e8 +OpenLibm.v0.8.7+0.powerpc64le-linux-gnu.tar.gz/md5/4fb864d30bcb12946228a37ef51577ec +OpenLibm.v0.8.7+0.powerpc64le-linux-gnu.tar.gz/sha512/c22c2ff04baa93547b006185138b162cc293f2c022433830cff14895ee49eb68d448d9731f0f92c8bfb4ab036648a2480be59cdf33b8ac52ab4d63131fde078c +OpenLibm.v0.8.7+0.riscv64-linux-gnu.tar.gz/md5/f09c74ff81b14c1d3c14263410ffbdd3 +OpenLibm.v0.8.7+0.riscv64-linux-gnu.tar.gz/sha512/7136dccc94d3324eb9f74ae05dc2e44cc5ddb3defdccb2e5f0b483205892111da7bf5bedb494190537d95fce45879096430d0298d6b520845aa804e94a047679 +OpenLibm.v0.8.7+0.x86_64-apple-darwin.tar.gz/md5/76c855df0fb8ceda368e6da3463429fc +OpenLibm.v0.8.7+0.x86_64-apple-darwin.tar.gz/sha512/0a3ff48d7c04cb9dc932b2d0a683063a366941b8f8f533b809d993621abd5f52606653afac98a045b7ead82f85394dfac728cb4a358f118779a3f72b53e0282a +OpenLibm.v0.8.7+0.x86_64-linux-gnu.tar.gz/md5/41c4d1525544c452d66c9fc11248a4fd +OpenLibm.v0.8.7+0.x86_64-linux-gnu.tar.gz/sha512/51abc0f0aa3b8a674c42228c41a87258d91e838f2bce7382d7da134f972ddd8b65a23330683d04702be21031db6a2b448081f5044b0640091e4aa47e9ffefe2e +OpenLibm.v0.8.7+0.x86_64-linux-musl.tar.gz/md5/781eeeffc650b41b25742005cab2dd3a +OpenLibm.v0.8.7+0.x86_64-linux-musl.tar.gz/sha512/945d3a1267d7435ccfb7342fe8d581dd28878ecac429d339924b3a49be6c25e7130759be68cf02e2e5c9dddf0ee6e5321bc9da8fbdf58f1e0dde3950ab866fe3 +OpenLibm.v0.8.7+0.x86_64-unknown-freebsd.tar.gz/md5/a947d491d424d891af54ef6db3990c52 +OpenLibm.v0.8.7+0.x86_64-unknown-freebsd.tar.gz/sha512/da477916536fcd7bb447dd6b7df1142c851a4ff027d5e1eca667736bd9eee8deda6aeacd7acf451b3246f16ddc8ec8f8fc35e8c4d4739858b8255b3d6be37b95 +OpenLibm.v0.8.7+0.x86_64-w64-mingw32.tar.gz/md5/26fcdd81d0e98542c6f7597993fabeee +OpenLibm.v0.8.7+0.x86_64-w64-mingw32.tar.gz/sha512/60705757778abb932009edf19250704ddb5f705a242e407195df9ced984f3855501f9034f170817dbd7770d6e8703353a4e0efb772c86c83d6d7a178c2aedb53 +openlibm-9fbeafcd4f1b6ef6aa3946c1c8faead50f38a94d.tar.gz/md5/7a2773e071b7aa1a39182dcb1e665a78 +openlibm-9fbeafcd4f1b6ef6aa3946c1c8faead50f38a94d.tar.gz/sha512/65f511aa223c9a1a7cc84b83415cc55a42786e08559620414e94aaa83414d32e868e6e9d3d460961dcb79998211fa80a04acd1c1f2bf9aa3fd49cd8324e2f9a0 diff --git a/deps/openlibm.version b/deps/openlibm.version index 788701a66301b..2d59624cbeb91 100644 --- a/deps/openlibm.version +++ b/deps/openlibm.version @@ -4,6 +4,6 @@ OPENLIBM_JLL_NAME := OpenLibm ## source build -OPENLIBM_VER := 0.8.5 -OPENLIBM_BRANCH=v0.8.5 -OPENLIBM_SHA1=db24332879c320606c37f77fea165e6ecb49153c +OPENLIBM_VER := 0.8.7 +OPENLIBM_BRANCH=v0.8.7 +OPENLIBM_SHA1=9fbeafcd4f1b6ef6aa3946c1c8faead50f38a94d diff --git a/stdlib/Manifest.toml b/stdlib/Manifest.toml index e0d3d3182b377..8d6093f744f14 100644 --- a/stdlib/Manifest.toml +++ b/stdlib/Manifest.toml @@ -163,7 +163,7 @@ version = "0.3.28+3" [[deps.OpenLibm_jll]] deps = ["Artifacts", "Libdl"] uuid = "05823500-19ac-5b8b-9628-191a04bc5112" -version = "0.8.5+0" +version = "0.8.7+0" [[deps.OpenSSL_jll]] deps = ["Artifacts", "Libdl"] diff --git a/stdlib/OpenLibm_jll/Project.toml b/stdlib/OpenLibm_jll/Project.toml index 431528ee3f400..a98bf97de0574 100644 --- a/stdlib/OpenLibm_jll/Project.toml +++ b/stdlib/OpenLibm_jll/Project.toml @@ -1,6 +1,6 @@ name = "OpenLibm_jll" uuid = "05823500-19ac-5b8b-9628-191a04bc5112" -version = "0.8.5+0" +version = "0.8.7+0" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" From 50e72b30ec819750ec1a7040325cbda5a3fb38cd Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Thu, 31 Jul 2025 12:11:43 -0400 Subject: [PATCH 23/23] replcompletions: Try to make the test more robust (#59166) This is an alternative to #59161, attempting to fix the same observed CI behavior. I don't think #59161 is the best way to fix it, as the point of these tests is to make sure that REPL completions looks up the PATH internally. Calling the path update function explicitly defeats that somewhat. The extra synchronization here to make this deterministic is messy, but I do think it makes the test closer to real-world usage. The core attempted fix here is to move the read of the PATH_ locals inside `maybe_spawn_cache_PATH` into the locked region. If they are not under the lock, they could be unconditionally overwritten by a second call to this function, causing issues in the state machine. I do not know whether this is the cause of the observed CI hangs, but it's worth fixing anyway. (cherry picked from commit 9a161192b21a70b0fb071f5d205a07b1ce6e0533) --- stdlib/REPL/src/REPLCompletions.jl | 22 ++++++++++++---------- stdlib/REPL/test/replcompletions.jl | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index e8dd01a0c3c89..03b4b4fec98f1 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -335,21 +335,23 @@ PATH_cache_condition::Union{Threads.Condition, Nothing} = nothing # used for syn next_cache_update::Float64 = 0.0 function maybe_spawn_cache_PATH() global PATH_cache_task, PATH_cache_condition, next_cache_update - # Extract to local variables to enable flow-sensitive type inference for these global variables - PATH_cache_task_local = PATH_cache_task - PATH_cache_condition_local = PATH_cache_condition @lock PATH_cache_lock begin + # Extract to local variables to enable flow-sensitive type inference for these global variables + PATH_cache_task_local = PATH_cache_task PATH_cache_task_local isa Task && !istaskdone(PATH_cache_task_local) && return time() < next_cache_update && return - PATH_cache_task = Threads.@spawn begin - REPLCompletions.cache_PATH() - @lock PATH_cache_lock begin - next_cache_update = time() + 10 # earliest next update can run is 10s after - PATH_cache_task = nothing # release memory when done - PATH_cache_condition_local !== nothing && notify(PATH_cache_condition_local) + PATH_cache_task = PATH_cache_task_local = Threads.@spawn begin + try + REPLCompletions.cache_PATH() + finally + @lock PATH_cache_lock begin + next_cache_update = time() + 10 # earliest next update can run is 10s after + PATH_cache_task = nothing # release memory when done + PATH_cache_condition_local = PATH_cache_condition + PATH_cache_condition_local !== nothing && notify(PATH_cache_condition_local) + end end end - PATH_cache_task_local = PATH_cache_task Base.errormonitor(PATH_cache_task_local) end end diff --git a/stdlib/REPL/test/replcompletions.jl b/stdlib/REPL/test/replcompletions.jl index 43bea08e285f1..b3b141425e1a4 100644 --- a/stdlib/REPL/test/replcompletions.jl +++ b/stdlib/REPL/test/replcompletions.jl @@ -1092,7 +1092,7 @@ function test_only_arm_cache_refresh() # force the next cache update to happen immediately REPL.REPLCompletions.next_cache_update = 0 end - return REPL.REPLCompletions.PATH_cache_condition + return nothing end function test_only_wait_cache_path_done()