diff --git a/base/abstractdict.jl b/base/abstractdict.jl index 62a5b3ee9e1b0..f291b8a582cf6 100644 --- a/base/abstractdict.jl +++ b/base/abstractdict.jl @@ -88,8 +88,8 @@ Return an iterator over all keys in a dictionary. When the keys are stored internally in a hash table, as is the case for `Dict`, the order in which they are returned may vary. -But `keys(a)` and `values(a)` both iterate `a` and -return the elements in the same order. +But `keys(a)`, `values(a)` and `pairs(a)` all iterate `a` +and return the elements in the same order. # Examples ```jldoctest @@ -114,8 +114,8 @@ Return an iterator over all values in a collection. When the values are stored internally in a hash table, as is the case for `Dict`, the order in which they are returned may vary. -But `keys(a)` and `values(a)` both iterate `a` and -return the elements in the same order. +But `keys(a)`, `values(a)` and `pairs(a)` all iterate `a` +and return the elements in the same order. # Examples ```jldoctest @@ -138,6 +138,10 @@ values(a::AbstractDict) = ValueIterator(a) Return an iterator over `key => value` pairs for any collection that maps a set of keys to a set of values. This includes arrays, where the keys are the array indices. +When the entries are stored internally in a hash table, +as is the case for `Dict`, the order in which they are returned may vary. +But `keys(a)`, `values(a)` and `pairs(a)` all iterate `a` +and return the elements in the same order. # Examples ```jldoctest diff --git a/base/binaryplatforms.jl b/base/binaryplatforms.jl index e0ee107c4ec73..088d7b4c7e995 100644 --- a/base/binaryplatforms.jl +++ b/base/binaryplatforms.jl @@ -591,6 +591,7 @@ const arch_mapping = Dict( "armv7l" => "arm(v7l)?", # if we just see `arm-linux-gnueabihf`, we assume it's `armv7l` "armv6l" => "armv6l", "powerpc64le" => "p(ower)?pc64le", + "riscv64" => "(rv64|riscv64)", ) # Keep this in sync with `CPUID.ISAs_by_family` # These are the CPUID side of the microarchitectures targeted by GCC flags in BinaryBuilder.jl diff --git a/base/broadcast.jl b/base/broadcast.jl index 91dbff6dc6ea3..3986d42d95f72 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -274,9 +274,14 @@ Base.@propagate_inbounds function Base.iterate(bc::Broadcasted, s) end Base.IteratorSize(::Type{T}) where {T<:Broadcasted} = Base.HasShape{ndims(T)}() -Base.ndims(BC::Type{<:Broadcasted{<:Any,Nothing}}) = _maxndims(fieldtype(BC, :args)) -Base.ndims(::Type{<:Broadcasted{<:AbstractArrayStyle{N},Nothing}}) where {N<:Integer} = N +Base.ndims(BC::Type{<:Broadcasted{<:Any,Nothing}}) = _maxndims_broadcasted(BC) +# the `AbstractArrayStyle` type parameter is required to be either equal to `Any` or be an `Int` value +Base.ndims(BC::Type{<:Broadcasted{<:AbstractArrayStyle{Any},Nothing}}) = _maxndims_broadcasted(BC) +Base.ndims(::Type{<:Broadcasted{<:AbstractArrayStyle{N},Nothing}}) where {N} = N::Int +function _maxndims_broadcasted(BC::Type{<:Broadcasted}) + _maxndims(fieldtype(BC, :args)) +end _maxndims(::Type{T}) where {T<:Tuple} = reduce(max, ntuple(n -> (F = fieldtype(T, n); F <: Tuple ? 1 : ndims(F)), Base._counttuple(T))) _maxndims(::Type{<:Tuple{T}}) where {T} = T <: Tuple ? 1 : ndims(T) function _maxndims(::Type{<:Tuple{T, S}}) where {T, S} diff --git a/base/compiler/effects.jl b/base/compiler/effects.jl index 166df78f3130c..ece549eda7a6d 100644 --- a/base/compiler/effects.jl +++ b/base/compiler/effects.jl @@ -329,6 +329,7 @@ is_inaccessiblemem_or_argmemonly(effects::Effects) = effects.inaccessiblememonly is_consistent_overlay(effects::Effects) = effects.nonoverlayed === CONSISTENT_OVERLAY +# (sync this with codegen.cpp and staticdata.c effects_foldable functions) function encode_effects(e::Effects) return ((e.consistent % UInt32) << 0) | ((e.effect_free % UInt32) << 3) | diff --git a/base/compiler/ssair/passes.jl b/base/compiler/ssair/passes.jl index 152fc3be3d1c3..3f5943d36938d 100644 --- a/base/compiler/ssair/passes.jl +++ b/base/compiler/ssair/passes.jl @@ -2075,18 +2075,19 @@ function adce_pass!(ir::IRCode, inlining::Union{Nothing,InliningState}=nothing) unionphi = unionphis[i] phi = unionphi[1] t = unionphi[2] + inst = compact.result[phi] if t === Union{} - stmt = compact[SSAValue(phi)][:stmt]::PhiNode + stmt = inst[:stmt]::PhiNode kill_phi!(compact, phi_uses, 1:length(stmt.values), SSAValue(phi), stmt, true) made_changes = true continue elseif t === Any continue - elseif ⊑(𝕃ₒ, compact.result[phi][:type], t) - continue end + ⊏ = strictpartialorder(𝕃ₒ) + t ⊏ inst[:type] || continue to_drop = Int[] - stmt = compact[SSAValue(phi)][:stmt] + stmt = inst[:stmt] stmt === nothing && continue stmt = stmt::PhiNode for i = 1:length(stmt.values) @@ -2098,7 +2099,8 @@ function adce_pass!(ir::IRCode, inlining::Union{Nothing,InliningState}=nothing) push!(to_drop, i) end end - compact.result[phi][:type] = t + inst[:type] = t + add_flag!(inst, IR_FLAG_REFINED) # t ⊏ inst[:type] kill_phi!(compact, phi_uses, to_drop, SSAValue(phi), stmt, false) made_changes = true end diff --git a/base/compiler/tfuncs.jl b/base/compiler/tfuncs.jl index 97d492304f678..baa364a69609b 100644 --- a/base/compiler/tfuncs.jl +++ b/base/compiler/tfuncs.jl @@ -587,8 +587,16 @@ add_tfunc(svec, 0, INT_INF, @nospecs((𝕃::AbstractLattice, args...)->SimpleVec return TypeVar end end - tv = TypeVar(nval, lb, ub) - return PartialTypeVar(tv, lb_certain, ub_certain) + lb_valid = lb isa Type || lb isa TypeVar + ub_valid = ub isa Type || ub isa TypeVar + if lb_valid && ub_valid + tv = TypeVar(nval, lb, ub) + return PartialTypeVar(tv, lb_certain, ub_certain) + elseif !lb_valid && lb_certain + return Union{} + elseif !ub_valid && ub_certain + return Union{} + end end return TypeVar end diff --git a/base/deepcopy.jl b/base/deepcopy.jl index c4f9ae1a6cb10..f60ce2043dd5a 100644 --- a/base/deepcopy.jl +++ b/base/deepcopy.jl @@ -120,11 +120,14 @@ function _deepcopy_memory_t(@nospecialize(x::Memory), T, stackdict::IdDict) end return dest end -@eval function deepcopy_internal(x::Array{T, N}, stackdict::IdDict) where {T, N} +function deepcopy_internal(x::Array{T, N}, stackdict::IdDict) where {T, N} if haskey(stackdict, x) return stackdict[x]::typeof(x) end - stackdict[x] = $(Expr(:new, :(Array{T, N}), :(deepcopy_internal(x.ref, stackdict)), :(x.size))) + y = stackdict[x] = Array{T, N}(undef, ntuple(Returns(0), Val{N}())) + setfield!(y, :ref, deepcopy_internal(x.ref, stackdict)) + setfield!(y, :size, x.size) + y end function deepcopy_internal(x::GenericMemoryRef, stackdict::IdDict) if haskey(stackdict, x) diff --git a/base/docs/basedocs.jl b/base/docs/basedocs.jl index be0ce0f216515..c1ab4857e2928 100644 --- a/base/docs/basedocs.jl +++ b/base/docs/basedocs.jl @@ -1460,7 +1460,7 @@ kw"new" """ where -The `where` keyword creates a type that is an iterated union of other types, over all +The `where` keyword creates a [`UnionAll`](@ref) type, which may be thought of as an iterated union of other types, over all values of some variable. For example `Vector{T} where T<:Real` includes all [`Vector`](@ref)s where the element type is some kind of `Real` number. diff --git a/base/loading.jl b/base/loading.jl index 3575bc5c0753f..bd4e3f3344dc4 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -1782,7 +1782,7 @@ function compilecache_path(pkg::PkgId; path = nothing isnothing(sourcepath) && error("Cannot locate source for $(repr("text/plain", pkg))") for path_to_try in cachepaths - staledeps = stale_cachefile(sourcepath, path_to_try, ignore_loaded = true, requested_flags=flags) + staledeps = stale_cachefile(sourcepath, path_to_try; ignore_loaded, requested_flags=flags) if staledeps === true continue end @@ -2555,7 +2555,7 @@ function _require(pkg::PkgId, env=nothing) parallel_precompile_attempted = true unlock(require_lock) try - Precompilation.precompilepkgs([pkg.name]; _from_loading=true) + Precompilation.precompilepkgs([pkg.name]; _from_loading=true, ignore_loaded=false) finally lock(require_lock) end diff --git a/base/mathconstants.jl b/base/mathconstants.jl index de6b98cea634d..d26f5115b5ccb 100644 --- a/base/mathconstants.jl +++ b/base/mathconstants.jl @@ -29,7 +29,7 @@ end Base.@assume_effects :foldable function (::Type{T})(x::_KnownIrrational, r::RoundingMode) where {T<:Union{Float32,Float64}} Base._irrational_to_float(T, x, r) end -Base.@assume_effects :foldable function rationalize(::Type{T}, x::_KnownIrrational; tol::Real=0) where {T<:Integer} +Base.@assume_effects :foldable function Base.rationalize(::Type{T}, x::_KnownIrrational; tol::Real=0) where {T<:Integer} Base._rationalize_irrational(T, x, tol) end Base.@assume_effects :foldable function Base.lessrational(rx::Rational, x::_KnownIrrational) diff --git a/base/meta.jl b/base/meta.jl index e648df29c12f9..e59462cf353bc 100644 --- a/base/meta.jl +++ b/base/meta.jl @@ -362,11 +362,29 @@ function _partially_inline!(@nospecialize(x), slot_replacements::Vector{Any}, x.edges .+= slot_offset return x end + if isa(x, Core.UpsilonNode) + if !isdefined(x, :val) + return x + end + return Core.UpsilonNode( + _partially_inline!(x.val, slot_replacements, type_signature, static_param_values, + slot_offset, statement_offset, boundscheck), + ) + end + if isa(x, Core.PhiCNode) + _partially_inline!(x.values, slot_replacements, type_signature, static_param_values, + slot_offset, statement_offset, boundscheck) + end if isa(x, Core.ReturnNode) + # Unreachable doesn't have val defined + if !isdefined(x, :val) + return x + else return Core.ReturnNode( _partially_inline!(x.val, slot_replacements, type_signature, static_param_values, slot_offset, statement_offset, boundscheck), ) + end end if isa(x, Core.GotoIfNot) return Core.GotoIfNot( @@ -376,6 +394,9 @@ function _partially_inline!(@nospecialize(x), slot_replacements::Vector{Any}, ) end if isa(x, Core.EnterNode) + if x.catch_dest == 0 + return x + end return Core.EnterNode(x, x.catch_dest + statement_offset) end if isa(x, Expr) diff --git a/base/precompilation.jl b/base/precompilation.jl index c822955f26bdd..254bab05a07dc 100644 --- a/base/precompilation.jl +++ b/base/precompilation.jl @@ -404,11 +404,12 @@ function precompilepkgs(pkgs::Vector{String}=String[]; configs::Union{Config,Vector{Config}}=(``=>Base.CacheFlags()), io::IO=stderr, # asking for timing disables fancy mode, as timing is shown in non-fancy mode - fancyprint::Bool = can_fancyprint(io) && !timing) + fancyprint::Bool = can_fancyprint(io) && !timing, + ignore_loaded::Bool=true) # monomorphize this to avoid latency problems _precompilepkgs(pkgs, internal_call, strict, warn_loaded, timing, _from_loading, configs isa Vector{Config} ? configs : [configs], - IOContext{IO}(io), fancyprint) + IOContext{IO}(io), fancyprint, ignore_loaded) end function _precompilepkgs(pkgs::Vector{String}, @@ -419,7 +420,8 @@ function _precompilepkgs(pkgs::Vector{String}, _from_loading::Bool, configs::Vector{Config}, io::IOContext{IO}, - fancyprint::Bool) + fancyprint::Bool, + ignore_loaded::Bool) requested_pkgs = copy(pkgs) # for understanding user intent time_start = time_ns() @@ -894,7 +896,7 @@ function _precompilepkgs(pkgs::Vector{String}, wait(was_processed[(dep,config)]) end circular = pkg in circular_deps - is_stale = !Base.isprecompiled(pkg; ignore_loaded=true, stale_cache, cachepath_cache, cachepaths, sourcepath, flags=cacheflags) + is_stale = !Base.isprecompiled(pkg; ignore_loaded, stale_cache, cachepath_cache, cachepaths, sourcepath, flags=cacheflags) if !circular && is_stale Base.acquire(parallel_limiter) is_direct_dep = pkg in direct_deps @@ -920,10 +922,10 @@ function _precompilepkgs(pkgs::Vector{String}, try # allows processes to wait if another process is precompiling a given package to # a functionally identical package cache (except for preferences, which may differ) - t = @elapsed ret = precompile_pkgs_maybe_cachefile_lock(io, print_lock, fancyprint, pkg_config, pkgspidlocked, hascolor) do + t = @elapsed ret = precompile_pkgs_maybe_cachefile_lock(io, print_lock, fancyprint, pkg_config, pkgspidlocked, hascolor, parallel_limiter, ignore_loaded) do Base.with_logger(Base.NullLogger()) do - # The false here means we ignore loaded modules, so precompile for a fresh session - keep_loaded_modules = false + # whether to respect already loaded dependency versions + keep_loaded_modules = !ignore_loaded # for extensions, any extension in our direct dependencies is one we have a right to load # for packages, we may load any extension (all possible triggers are accounted for above) loadable_exts = haskey(exts, pkg) ? filter((dep)->haskey(exts, dep), depsmap[pkg]) : nothing @@ -1008,9 +1010,11 @@ function _precompilepkgs(pkgs::Vector{String}, plural1 = length(configs) > 1 ? "dependency configurations" : n_loaded == 1 ? "dependency" : "dependencies" plural2 = n_loaded == 1 ? "a different version is" : "different versions are" plural3 = n_loaded == 1 ? "" : "s" + plural4 = n_loaded == 1 ? "this package" : "these packages" print(iostr, "\n ", color_string(string(n_loaded), Base.warn_color()), - " $(plural1) precompiled but $(plural2) currently loaded. Restart julia to access the new version$(plural3)" + " $(plural1) precompiled but $(plural2) currently loaded. Restart julia to access the new version$(plural3). \ + Otherwise, loading dependents of $(plural4) may trigger further precompilation to work with the unexpected version$(plural3)." ) end if !isempty(precomperr_deps) @@ -1069,7 +1073,7 @@ function _precompilepkgs(pkgs::Vector{String}, direct = strict ? "" : "direct " err_msg = "The following $n_direct_errs $(direct)dependenc$(pluralde) failed to precompile:\n$(String(take!(err_str)))" if internal_call # aka. auto-precompilation - if isinteractive() && !get(ENV, "CI", false) + if isinteractive() plural1 = length(failed_deps) == 1 ? "y" : "ies" println(io, " ", color_string("$(length(failed_deps))", Base.error_color()), " dependenc$(plural1) errored.") println(io, " For a report of the errors see `julia> err`. To retry use `pkg> precompile`") @@ -1101,7 +1105,7 @@ function _color_string(cstr::String, col::Union{Int64, Symbol}, hascolor) end # Can be merged with `maybe_cachefile_lock` in loading? -function precompile_pkgs_maybe_cachefile_lock(f, io::IO, print_lock::ReentrantLock, fancyprint::Bool, pkg_config, pkgspidlocked, hascolor) +function precompile_pkgs_maybe_cachefile_lock(f, io::IO, print_lock::ReentrantLock, fancyprint::Bool, pkg_config, pkgspidlocked, hascolor, parallel_limiter::Base.Semaphore, ignore_loaded::Bool) pkg, config = pkg_config flags, cacheflags = config FileWatching = Base.loaded_modules[Base.PkgId(Base.UUID("7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee"), "FileWatching")] @@ -1122,15 +1126,21 @@ function precompile_pkgs_maybe_cachefile_lock(f, io::IO, print_lock::ReentrantLo !fancyprint && lock(print_lock) do println(io, " ", pkg.name, _color_string(" Being precompiled by $(pkgspidlocked[pkg_config])", Base.info_color(), hascolor)) end - # wait until the lock is available - FileWatching.mkpidlock(pidfile; stale_age) do - # double-check in case the other process crashed or the lock expired - if Base.isprecompiled(pkg; ignore_loaded=true, flags=cacheflags) # don't use caches for this as the env state will have changed - return nothing # returning nothing indicates a process waited for another - else - delete!(pkgspidlocked, pkg_config) - return f() # precompile - end + Base.release(parallel_limiter) # release so other work can be done while waiting + try + # wait until the lock is available + @invokelatest Base.mkpidlock_hook(() -> begin + # double-check in case the other process crashed or the lock expired + if Base.isprecompiled(pkg; ignore_loaded, flags=cacheflags) # don't use caches for this as the env state will have changed + return nothing # returning nothing indicates a process waited for another + else + delete!(pkgspidlocked, pkg_config) + Base.acquire(f, parallel_limiter) # precompile + end + end, + pidfile; stale_age) + finally + Base.acquire(parallel_limiter) # re-acquire so the outer release is balanced end end return cachefile diff --git a/base/special/exp.jl b/base/special/exp.jl index 8e940a4d85ad9..32de6b9be296d 100644 --- a/base/special/exp.jl +++ b/base/special/exp.jl @@ -216,6 +216,7 @@ end small_part = muladd(jU, expm1b_kernel(base, r), jL) + jU if !(abs(x) <= SUBNORM_EXP(base, T)) + isnan(x) && return x x >= MAX_EXP(base, T) && return Inf x <= MIN_EXP(base, T) && return 0.0 if k <= -53 @@ -243,6 +244,7 @@ end hi, lo = Base.canonicalize2(1.0, kern) small_part = fma(jU, hi, muladd(jU, (lo+xlo), very_small)) if !(abs(x) <= SUBNORM_EXP(base, T)) + isnan(x) && return x x >= MAX_EXP(base, T) && return Inf x <= MIN_EXP(base, T) && return 0.0 if k <= -53 diff --git a/base/subarray.jl b/base/subarray.jl index d7011c50421c0..56bd2ca4ea350 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -295,18 +295,18 @@ reindex(idxs::Tuple{Slice, Vararg{Any}}, subidxs::Tuple{Any, Vararg{Any}}) = # Re-index into parent vectors with one subindex reindex(idxs::Tuple{AbstractVector, Vararg{Any}}, subidxs::Tuple{Any, Vararg{Any}}) = - (@_propagate_inbounds_meta; (maybeview(idxs[1], subidxs[1]), reindex(tail(idxs), tail(subidxs))...)) + (@_propagate_inbounds_meta; (idxs[1][subidxs[1]], reindex(tail(idxs), tail(subidxs))...)) # Parent matrices are re-indexed with two sub-indices reindex(idxs::Tuple{AbstractMatrix, Vararg{Any}}, subidxs::Tuple{Any, Any, Vararg{Any}}) = - (@_propagate_inbounds_meta; (maybeview(idxs[1], subidxs[1], subidxs[2]), reindex(tail(idxs), tail(tail(subidxs)))...)) + (@_propagate_inbounds_meta; (idxs[1][subidxs[1], subidxs[2]], reindex(tail(idxs), tail(tail(subidxs)))...)) # In general, we index N-dimensional parent arrays with N indices @generated function reindex(idxs::Tuple{AbstractArray{T,N}, Vararg{Any}}, subidxs::Tuple{Vararg{Any}}) where {T,N} if length(subidxs.parameters) >= N subs = [:(subidxs[$d]) for d in 1:N] tail = [:(subidxs[$d]) for d in N+1:length(subidxs.parameters)] - :(@_propagate_inbounds_meta; (maybeview(idxs[1], $(subs...)), reindex(tail(idxs), ($(tail...),))...)) + :(@_propagate_inbounds_meta; (idxs[1][$(subs...)], reindex(tail(idxs), ($(tail...),))...)) else :(throw(ArgumentError("cannot re-index SubArray with fewer indices than dimensions\nThis should not occur; please submit a bug report."))) end diff --git a/contrib/generate_precompile.jl b/contrib/generate_precompile.jl index 49bcf3f43ea41..43b6f89712d2b 100644 --- a/contrib/generate_precompile.jl +++ b/contrib/generate_precompile.jl @@ -131,60 +131,56 @@ for match = Base._methods(+, (Int, Int), -1, Base.get_world_counter()) m = match.method delete!(push!(Set{Method}(), m), m) copy(Core.Compiler.retrieve_code_info(Core.Compiler.specialize_method(match), typemax(UInt))) - - empty!(Set()) - push!(push!(Set{Union{GlobalRef,Symbol}}(), :two), GlobalRef(Base, :two)) - (setindex!(Dict{String,Base.PkgId}(), Base.PkgId(Base), "file.jl"))["file.jl"] - (setindex!(Dict{Symbol,Vector{Int}}(), [1], :two))[:two] - (setindex!(Dict{Base.PkgId,String}(), "file.jl", Base.PkgId(Base)))[Base.PkgId(Base)] - (setindex!(Dict{Union{GlobalRef,Symbol}, Vector{Int}}(), [1], :two))[:two] - (setindex!(IdDict{Type, Union{Missing, Vector{Tuple{LineNumberNode, Expr}}}}(), missing, Int))[Int] - Dict{Symbol, Union{Nothing, Bool, Symbol}}(:one => false)[:one] - Dict(Base => [:(1+1)])[Base] - Dict(:one => [1])[:one] - Dict("abc" => Set())["abc"] - pushfirst!([], sum) - get(Base.pkgorigins, Base.PkgId(Base), nothing) - sort!([1,2,3]) - unique!([1,2,3]) - cumsum([1,2,3]) - append!(Int[], BitSet()) - isempty(BitSet()) - delete!(BitSet([1,2]), 3) - deleteat!(Int32[1,2,3], [1,3]) - deleteat!(Any[1,2,3], [1,3]) - Core.svec(1, 2) == Core.svec(3, 4) - any(t->t[1].line > 1, [(LineNumberNode(2,:none), :(1+1))]) - - # Code loading uses this - sortperm(mtime.(readdir(".")), rev=true) - # JLLWrappers uses these - Dict{Base.UUID,Set{String}}()[Base.UUID("692b3bcd-3c85-4b1f-b108-f13ce0eb3210")] = Set{String}() - get!(Set{String}, Dict{Base.UUID,Set{String}}(), Base.UUID("692b3bcd-3c85-4b1f-b108-f13ce0eb3210")) - eachindex(IndexLinear(), Expr[]) - push!(Expr[], Expr(:return, false)) - vcat(String[], String[]) - k, v = (:hello => nothing) - Base.print_time_imports_report(Base) - Base.print_time_imports_report_init(Base) - - # Preferences uses these - get(Dict{String,Any}(), "missing", nothing) - delete!(Dict{String,Any}(), "missing") - for (k, v) in Dict{String,Any}() - println(k) - end - - # interactive startup uses this - write(IOBuffer(), "") - - # Not critical, but helps hide unrelated compilation from @time when using --trace-compile. - f55729() = Base.Experimental.@force_compile - @time @eval f55729() - @time @eval f55729() - break # only actually need to do this once end +empty!(Set()) +push!(push!(Set{Union{GlobalRef,Symbol}}(), :two), GlobalRef(Base, :two)) +(setindex!(Dict{String,Base.PkgId}(), Base.PkgId(Base), "file.jl"))["file.jl"] +(setindex!(Dict{Symbol,Vector{Int}}(), [1], :two))[:two] +(setindex!(Dict{Base.PkgId,String}(), "file.jl", Base.PkgId(Base)))[Base.PkgId(Base)] +(setindex!(Dict{Union{GlobalRef,Symbol}, Vector{Int}}(), [1], :two))[:two] +(setindex!(IdDict{Type, Union{Missing, Vector{Tuple{LineNumberNode, Expr}}}}(), missing, Int))[Int] +Dict{Symbol, Union{Nothing, Bool, Symbol}}(:one => false)[:one] +Dict(Base => [:(1+1)])[Base] +Dict(:one => [1])[:one] +Dict("abc" => Set())["abc"] +pushfirst!([], sum) +get(Base.pkgorigins, Base.PkgId(Base), nothing) +sort!([1,2,3]) +unique!([1,2,3]) +cumsum([1,2,3]) +append!(Int[], BitSet()) +isempty(BitSet()) +delete!(BitSet([1,2]), 3) +deleteat!(Int32[1,2,3], [1,3]) +deleteat!(Any[1,2,3], [1,3]) +Core.svec(1, 2) == Core.svec(3, 4) +any(t->t[1].line > 1, [(LineNumberNode(2,:none), :(1+1))]) + +# Code loading uses this +sortperm(mtime.(readdir(".")), rev=true) +# JLLWrappers uses these +Dict{Base.UUID,Set{String}}()[Base.UUID("692b3bcd-3c85-4b1f-b108-f13ce0eb3210")] = Set{String}() +get!(Set{String}, Dict{Base.UUID,Set{String}}(), Base.UUID("692b3bcd-3c85-4b1f-b108-f13ce0eb3210")) +eachindex(IndexLinear(), Expr[]) +push!(Expr[], Expr(:return, false)) +vcat(String[], String[]) +k, v = (:hello => nothing) +Base.print_time_imports_report(Base) +Base.print_time_imports_report_init(Base) + +# Preferences uses these +get(Dict{String,Any}(), "missing", nothing) +delete!(Dict{String,Any}(), "missing") +for (k, v) in Dict{String,Any}() + println(k) +end + +# interactive startup uses this +write(IOBuffer(), "") + +# precompile @time report generation and printing +@time @eval Base.Experimental.@force_compile """ julia_exepath() = joinpath(Sys.BINDIR, Base.julia_exename()) diff --git a/deps/checksums/Pkg-2eb8ae5b8f421fc77295f9cf382132d39e14d16f.tar.gz/md5 b/deps/checksums/Pkg-2eb8ae5b8f421fc77295f9cf382132d39e14d16f.tar.gz/md5 new file mode 100644 index 0000000000000..94028daf1ceae --- /dev/null +++ b/deps/checksums/Pkg-2eb8ae5b8f421fc77295f9cf382132d39e14d16f.tar.gz/md5 @@ -0,0 +1 @@ +04462f4ccf05a569002927e662938857 diff --git a/deps/checksums/Pkg-2eb8ae5b8f421fc77295f9cf382132d39e14d16f.tar.gz/sha512 b/deps/checksums/Pkg-2eb8ae5b8f421fc77295f9cf382132d39e14d16f.tar.gz/sha512 new file mode 100644 index 0000000000000..4b719cfd15d33 --- /dev/null +++ b/deps/checksums/Pkg-2eb8ae5b8f421fc77295f9cf382132d39e14d16f.tar.gz/sha512 @@ -0,0 +1 @@ +20d84f39511ab5229e1d2d542e204fe8df016e81bbe2f684c4713d04945d1b8fa89b506031847c1a754368aa6fed48ee8c6cb8f28219fbc210179883803d46bf diff --git a/deps/checksums/Pkg-64bf95a4847898cf70de54d0c861c877ed5c1595.tar.gz/md5 b/deps/checksums/Pkg-64bf95a4847898cf70de54d0c861c877ed5c1595.tar.gz/md5 deleted file mode 100644 index 15b698352e581..0000000000000 --- a/deps/checksums/Pkg-64bf95a4847898cf70de54d0c861c877ed5c1595.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -219e6af925739b706b73d74f2059b6a4 diff --git a/deps/checksums/Pkg-64bf95a4847898cf70de54d0c861c877ed5c1595.tar.gz/sha512 b/deps/checksums/Pkg-64bf95a4847898cf70de54d0c861c877ed5c1595.tar.gz/sha512 deleted file mode 100644 index 1583b39817edc..0000000000000 --- a/deps/checksums/Pkg-64bf95a4847898cf70de54d0c861c877ed5c1595.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -23b24d5c1cbe6e16b2388e79c233877d77471d3766002e02d0160eb1020e11c42b0c300b70d85c6b89a11e5de83708a3165e40d44cc21f011286eb6f096f2496 diff --git a/doc/src/manual/complex-and-rational-numbers.md b/doc/src/manual/complex-and-rational-numbers.md index 9cab2ed1e4f24..d1d6ffeca245f 100644 --- a/doc/src/manual/complex-and-rational-numbers.md +++ b/doc/src/manual/complex-and-rational-numbers.md @@ -254,13 +254,30 @@ julia> float(3//4) ``` Conversion from rational to floating-point respects the following identity for any integral values -of `a` and `b`, with the exception of the two cases `b == 0` and `a == 0 && b < 0`: +of `a` and `b`, except when `a==0 && b <= 0`: ```jldoctest julia> a = 1; b = 2; julia> isequal(float(a//b), a/b) true + +julia> a, b = 0, 0 +(0, 0) + +julia> float(a//b) +ERROR: ArgumentError: invalid rational: zero(Int64)//zero(Int64) +Stacktrace: +[...] + +julia> a/b +NaN + +julia> a, b = 0, -1 +(0, -1) + +julia> float(a//b), a/b +(0.0, -0.0) ``` Constructing infinite rational values is acceptable: diff --git a/src/codegen.cpp b/src/codegen.cpp index a0a4136ca6224..244bee17b2bbe 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -9674,10 +9674,10 @@ jl_llvm_functions_t jl_emit_codeinst( // Julia-level optimization will never need to see it else if (jl_is_method(def) && // don't delete toplevel code inferred != jl_nothing && // and there is something to delete (test this before calling jl_ir_inlining_cost) - !effects_foldable(codeinst->ipo_purity_bits) && // don't delete code we may want for irinterp - ((jl_ir_inlining_cost(inferred) == UINT16_MAX) || // don't delete inlineable code - jl_atomic_load_relaxed(&codeinst->invoke) == jl_fptr_const_return_addr) && // unless it is constant - !(params.imaging_mode || jl_options.incremental)) { // don't delete code when generating a precompile file + ((!effects_foldable(codeinst->ipo_purity_bits) && // don't delete code we may want for irinterp + (jl_ir_inlining_cost(inferred) == UINT16_MAX) && // don't delete inlineable code + !jl_generating_output()) || // don't delete code when generating a precompile file, trading memory in the short term for avoiding likely duplicating inference work for aotcompile + jl_atomic_load_relaxed(&codeinst->invoke) == jl_fptr_const_return_addr)) { // unless it is constant (although this shouldn't have had code in the first place) jl_atomic_store_release(&codeinst->inferred, jl_nothing); } } diff --git a/src/gc-stacks.c b/src/gc-stacks.c index 82094035349b3..7746aa12fa2bf 100644 --- a/src/gc-stacks.c +++ b/src/gc-stacks.c @@ -43,7 +43,7 @@ static void *malloc_stack(size_t bufsz) JL_NOTSAFEPOINT } -static void free_stack(void *stkbuf, size_t bufsz) +static void free_stack(void *stkbuf, size_t bufsz) JL_NOTSAFEPOINT { VirtualFree(stkbuf, 0, MEM_RELEASE); jl_atomic_fetch_add(&num_stack_mappings, -1); @@ -68,7 +68,7 @@ static void *malloc_stack(size_t bufsz) JL_NOTSAFEPOINT return stk; } -static void free_stack(void *stkbuf, size_t bufsz) +static void free_stack(void *stkbuf, size_t bufsz) JL_NOTSAFEPOINT { munmap(stkbuf, bufsz); jl_atomic_fetch_add(&num_stack_mappings, -1); @@ -110,7 +110,7 @@ static unsigned select_pool(size_t nb) JL_NOTSAFEPOINT } -static void _jl_free_stack(jl_ptls_t ptls, void *stkbuf, size_t bufsz) +static void _jl_free_stack(jl_ptls_t ptls, void *stkbuf, size_t bufsz) JL_NOTSAFEPOINT { #ifdef _COMPILER_ASAN_ENABLED_ __asan_unpoison_stack_memory((uintptr_t)stkbuf, bufsz); diff --git a/src/gc.c b/src/gc.c index fd9ad71d8afe0..c5bdb9eead8e4 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1255,8 +1255,7 @@ static void sweep_malloced_memory(void) JL_NOTSAFEPOINT *pma = nxt; int isaligned = (uintptr_t)ma->a & 1; jl_gc_free_memory(a, isaligned); - ma->next = ptls2->heap.mafreelist; - ptls2->heap.mafreelist = ma; + free(ma); } gc_time_count_mallocd_memory(bits); ma = nxt; @@ -3854,10 +3853,10 @@ JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection) jl_atomic_store_release(&ptls->gc_state, JL_GC_STATE_WAITING); // `jl_safepoint_start_gc()` makes sure only one thread can run the GC. uint64_t t0 = jl_hrtime(); - if (!jl_safepoint_start_gc()) { + if (!jl_safepoint_start_gc(ct)) { // either another thread is running GC, or the GC got disabled just now. jl_gc_state_set(ptls, old_state, JL_GC_STATE_WAITING); - jl_safepoint_wait_thread_resume(); // block in thread-suspend now if requested, after clearing the gc_state + jl_safepoint_wait_thread_resume(ct); // block in thread-suspend now if requested, after clearing the gc_state return; } @@ -3911,7 +3910,7 @@ JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection) jl_safepoint_end_gc(); jl_gc_state_set(ptls, old_state, JL_GC_STATE_WAITING); JL_PROBE_GC_END(); - jl_safepoint_wait_thread_resume(); // block in thread-suspend now if requested, after clearing the gc_state + jl_safepoint_wait_thread_resume(ct); // block in thread-suspend now if requested, after clearing the gc_state // Only disable finalizers on current thread // Doing this on all threads is racy (it's impossible to check diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index d7fef443771bc..b3ed1e069de16 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -500,7 +500,15 @@ jl_code_instance_t *jl_generate_fptr_impl(jl_method_instance_t *mi JL_PROPAGATES } else { // identify whether this is an invalidated method that is being recompiled - is_recompile = jl_atomic_load_relaxed(&mi->cache) != NULL; + // Is a recompile if there is cached code, and it was compiled (not only inferred) before + jl_code_instance_t *codeinst_old = jl_atomic_load_relaxed(&mi->cache); + while (codeinst_old != NULL) { + if (jl_atomic_load_relaxed(&codeinst_old->invoke) != NULL) { + is_recompile = 1; + break; + } + codeinst_old = jl_atomic_load_relaxed(&codeinst_old->next); + } } if (src == NULL && jl_is_method(mi->def.method) && jl_symbol_name(mi->def.method->name)[0] != '@') { diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 17092ca4cf751..280acf1223c5d 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -4363,15 +4363,16 @@ f(x) = yt(x) (define (pop-handler-list src-tokens dest-tokens lab) (if (eq? src-tokens dest-tokens) #f - (let loop ((s src-tokens) - (l '())) - (if (not (pair? s)) - (if (null? lab) - (error "Attempt to jump into catch block") - (error (string "cannot goto label \"" lab "\" inside try/catch block")))) - (if (eq? (cdr s) dest-tokens) - (cons (car s) l) - (loop (cdr s) (cons (car s) l)))))) + (reverse + (let loop ((s src-tokens) + (l '())) + (if (not (pair? s)) + (if (null? lab) + (error "Attempt to jump into catch block") + (error (string "cannot goto label \"" lab "\" inside try/catch block")))) + (if (eq? (cdr s) dest-tokens) + (cons (car s) l) + (loop (cdr s) (cons (car s) l))))))) (define (emit-return tail x) (define (emit- x) (let* ((tmp (if ((if (null? catch-token-stack) valid-ir-return? simple-atom?) x) diff --git a/src/julia.h b/src/julia.h index e97b61f85a230..e321fe0ef9ee5 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1043,7 +1043,7 @@ JL_DLLEXPORT jl_value_t *jl_gc_alloc_2w(void); JL_DLLEXPORT jl_value_t *jl_gc_alloc_3w(void); JL_DLLEXPORT jl_value_t *jl_gc_allocobj(size_t sz); JL_DLLEXPORT void *jl_malloc_stack(size_t *bufsz, struct _jl_task_t *owner) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_free_stack(void *stkbuf, size_t bufsz); +JL_DLLEXPORT void jl_free_stack(void *stkbuf, size_t bufsz) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_gc_use(jl_value_t *a); // Set GC memory trigger in bytes for greedy memory collecting JL_DLLEXPORT void jl_gc_set_max_memory(uint64_t max_mem); diff --git a/src/julia_internal.h b/src/julia_internal.h index 4050410a1b1b2..1c2d071d1a6cd 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -967,7 +967,7 @@ void jl_safepoint_init(void); // before calling this function. If the calling thread is to run the GC, // it should also wait for the mutator threads to hit a safepoint **AFTER** // this function returns -int jl_safepoint_start_gc(void); +int jl_safepoint_start_gc(jl_task_t *ct); // Can only be called by the thread that have got a `1` return value from // `jl_safepoint_start_gc()`. This disables the safepoint (for GC, // the `mprotect` may not be removed if there's pending SIGINT) and wake @@ -977,9 +977,8 @@ void jl_safepoint_end_gc(void); // Wait for the GC to finish // This function does **NOT** modify the `gc_state` to inform the GC thread // The caller should set it **BEFORE** calling this function. -void jl_safepoint_wait_gc(void) JL_NOTSAFEPOINT; -void jl_safepoint_wait_thread_resume(void) JL_NOTSAFEPOINT; - +void jl_safepoint_wait_gc(jl_task_t *ct) JL_NOTSAFEPOINT; +void jl_safepoint_wait_thread_resume(jl_task_t *ct) JL_NOTSAFEPOINT; // Set pending sigint and enable the mechanisms to deliver the sigint. void jl_safepoint_enable_sigint(void); // If the safepoint is enabled to deliver sigint, disable it @@ -1006,7 +1005,7 @@ JL_DLLEXPORT void jl_pgcstack_getkey(jl_get_pgcstack_func **f, jl_pgcstack_key_t extern pthread_mutex_t in_signal_lock; #endif -void jl_set_gc_and_wait(void); // n.b. not used on _OS_DARWIN_ +void jl_set_gc_and_wait(jl_task_t *ct); // n.b. not used on _OS_DARWIN_ // Query if a Julia object is if a permalloc region (due to part of a sys- pkg-image) STATIC_INLINE size_t n_linkage_blobs(void) JL_NOTSAFEPOINT diff --git a/src/safepoint.c b/src/safepoint.c index 22cda0a89444d..d1012122e9541 100644 --- a/src/safepoint.c +++ b/src/safepoint.c @@ -158,17 +158,16 @@ void jl_gc_wait_for_the_world(jl_ptls_t* gc_all_tls_states, int gc_n_threads) } } -int jl_safepoint_start_gc(void) +int jl_safepoint_start_gc(jl_task_t *ct) { // The thread should have just set this before entry - assert(jl_atomic_load_relaxed(&jl_current_task->ptls->gc_state) == JL_GC_STATE_WAITING); + assert(jl_atomic_load_relaxed(&ct->ptls->gc_state) == JL_GC_STATE_WAITING); uv_mutex_lock(&safepoint_lock); uv_cond_broadcast(&safepoint_cond_begin); // make sure we are permitted to run GC now (we might be required to stop instead) - jl_task_t *ct = jl_current_task; while (jl_atomic_load_relaxed(&ct->ptls->suspend_count)) { uv_mutex_unlock(&safepoint_lock); - jl_safepoint_wait_thread_resume(); + jl_safepoint_wait_thread_resume(ct); uv_mutex_lock(&safepoint_lock); } // In case multiple threads enter the GC at the same time, only allow @@ -178,7 +177,7 @@ int jl_safepoint_start_gc(void) uint32_t running = 0; if (!jl_atomic_cmpswap(&jl_gc_running, &running, 1)) { uv_mutex_unlock(&safepoint_lock); - jl_safepoint_wait_gc(); + jl_safepoint_wait_gc(ct); return 0; } // Foreign thread adoption disables the GC and waits for it to finish, however, that may @@ -213,9 +212,8 @@ void jl_safepoint_end_gc(void) uv_cond_broadcast(&safepoint_cond_end); } -void jl_set_gc_and_wait(void) // n.b. not used on _OS_DARWIN_ +void jl_set_gc_and_wait(jl_task_t *ct) // n.b. not used on _OS_DARWIN_ { - jl_task_t *ct = jl_current_task; // reading own gc state doesn't need atomic ops since no one else // should store to it. int8_t state = jl_atomic_load_relaxed(&ct->ptls->gc_state); @@ -223,18 +221,19 @@ void jl_set_gc_and_wait(void) // n.b. not used on _OS_DARWIN_ uv_mutex_lock(&safepoint_lock); uv_cond_broadcast(&safepoint_cond_begin); uv_mutex_unlock(&safepoint_lock); - jl_safepoint_wait_gc(); + jl_safepoint_wait_gc(ct); jl_atomic_store_release(&ct->ptls->gc_state, state); - jl_safepoint_wait_thread_resume(); // block in thread-suspend now if requested, after clearing the gc_state + jl_safepoint_wait_thread_resume(ct); // block in thread-suspend now if requested, after clearing the gc_state } // this is the core of jl_set_gc_and_wait -void jl_safepoint_wait_gc(void) JL_NOTSAFEPOINT +void jl_safepoint_wait_gc(jl_task_t *ct) JL_NOTSAFEPOINT { - jl_task_t *ct = jl_current_task; (void)ct; - JL_TIMING_SUSPEND_TASK(GC_SAFEPOINT, ct); - // The thread should have set this is already - assert(jl_atomic_load_relaxed(&ct->ptls->gc_state) != JL_GC_STATE_UNSAFE); + if (ct) { + JL_TIMING_SUSPEND_TASK(GC_SAFEPOINT, ct); + // The thread should have set this is already + assert(jl_atomic_load_relaxed(&ct->ptls->gc_state) != JL_GC_STATE_UNSAFE); + } // Use normal volatile load in the loop for speed until GC finishes. // Then use an acquire load to make sure the GC result is visible on this thread. while (jl_atomic_load_relaxed(&jl_gc_running) || jl_atomic_load_acquire(&jl_gc_running)) { @@ -249,9 +248,8 @@ void jl_safepoint_wait_gc(void) JL_NOTSAFEPOINT } // equivalent to jl_set_gc_and_wait, but waiting on resume-thread lock instead -void jl_safepoint_wait_thread_resume(void) +void jl_safepoint_wait_thread_resume(jl_task_t *ct) { - jl_task_t *ct = jl_current_task; // n.b. we do not permit a fast-path here that skips the lock acquire since // we otherwise have no synchronization point to ensure that this thread // will observe the change to the safepoint, even though the other thread @@ -305,7 +303,7 @@ int jl_safepoint_suspend_thread(int tid, int waitstate) // not, so assume it is running GC and wait for GC to finish first. // It will be unable to reenter helping with GC because we have // changed its safepoint page. - jl_set_gc_and_wait(); + jl_set_gc_and_wait(jl_current_task); } while (jl_atomic_load_acquire(&ptls2->suspend_count) != 0) { int8_t state2 = jl_atomic_load_acquire(&ptls2->gc_state); diff --git a/src/signals-mach.c b/src/signals-mach.c index db241657864c2..618ad5fcadb0c 100644 --- a/src/signals-mach.c +++ b/src/signals-mach.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "mach_excServer.c" #ifdef MAC_OS_X_VERSION_10_9 @@ -47,14 +48,31 @@ static arraylist_t suspended_threads; extern uv_mutex_t safepoint_lock; extern uv_cond_t safepoint_cond_begin; +#define GC_STATE_SHIFT 8*sizeof(int16_t) +static inline int8_t decode_gc_state(uintptr_t item) +{ + return (int8_t)(item >> GC_STATE_SHIFT); +} + +static inline int16_t decode_tid(uintptr_t item) +{ + return (int16_t)item; +} + +static inline uintptr_t encode_item(int16_t tid, int8_t gc_state) +{ + return (uintptr_t)tid | ((uintptr_t)gc_state << GC_STATE_SHIFT); +} + // see jl_safepoint_wait_thread_resume void jl_safepoint_resume_thread_mach(jl_ptls_t ptls2, int16_t tid2) { // must be called with uv_mutex_lock(&safepoint_lock) and uv_mutex_lock(&ptls2->sleep_lock) held (in that order) for (size_t i = 0; i < suspended_threads.len; i++) { uintptr_t item = (uintptr_t)suspended_threads.items[i]; - int16_t tid = (int16_t)item; - int8_t gc_state = (int8_t)(item >> 8); + + int16_t tid = decode_tid(item); + int8_t gc_state = decode_gc_state(item); if (tid != tid2) continue; jl_atomic_store_release(&ptls2->gc_state, gc_state); @@ -71,8 +89,8 @@ void jl_mach_gc_end(void) size_t j = 0; for (size_t i = 0; i < suspended_threads.len; i++) { uintptr_t item = (uintptr_t)suspended_threads.items[i]; - int16_t tid = (int16_t)item; - int8_t gc_state = (int8_t)(item >> 8); + int16_t tid = decode_tid(item); + int8_t gc_state = decode_gc_state(item); jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[tid]; uv_mutex_lock(&ptls2->sleep_lock); if (jl_atomic_load_relaxed(&ptls2->suspend_count) == 0) { @@ -117,7 +135,7 @@ static void jl_mach_gc_wait(jl_ptls_t ptls2, mach_port_t thread, int16_t tid) // triggers a SIGSEGV and gets handled by the usual codepath for unix. int8_t gc_state = jl_atomic_load_acquire(&ptls2->gc_state); jl_atomic_store_release(&ptls2->gc_state, JL_GC_STATE_WAITING); - uintptr_t item = tid | (((uintptr_t)gc_state) << 16); + uintptr_t item = encode_item(tid, gc_state); arraylist_push(&suspended_threads, (void*)item); thread_suspend(thread); } diff --git a/src/signals-unix.c b/src/signals-unix.c index 2aafd335a68b8..a889483804e3e 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -365,7 +365,7 @@ JL_NO_ASAN static void segv_handler(int sig, siginfo_t *info, void *context) return; } if (sig == SIGSEGV && info->si_code == SEGV_ACCERR && jl_addr_is_safepoint((uintptr_t)info->si_addr) && !is_write_fault(context)) { - jl_set_gc_and_wait(); + jl_set_gc_and_wait(ct); // Do not raise sigint on worker thread if (jl_atomic_load_relaxed(&ct->tid) != 0) return; diff --git a/src/signals-win.c b/src/signals-win.c index a2980a0c063d9..bca62f21bcec9 100644 --- a/src/signals-win.c +++ b/src/signals-win.c @@ -250,7 +250,7 @@ LONG WINAPI jl_exception_handler(struct _EXCEPTION_POINTERS *ExceptionInfo) break; case EXCEPTION_ACCESS_VIOLATION: if (jl_addr_is_safepoint(ExceptionInfo->ExceptionRecord->ExceptionInformation[1])) { - jl_set_gc_and_wait(); + jl_set_gc_and_wait(ct); // Do not raise sigint on worker thread if (ptls->tid != 0) return EXCEPTION_CONTINUE_EXECUTION; diff --git a/src/staticdata.c b/src/staticdata.c index 76bb488731a92..2fa500d053d4e 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -725,6 +725,16 @@ static uintptr_t jl_fptr_id(void *fptr) return *(uintptr_t*)pbp; } +static int effects_foldable(uint32_t effects) +{ + // N.B.: This needs to be kept in sync with Core.Compiler.is_foldable(effects, true) + return ((effects & 0x7) == 0) && // is_consistent(effects) + (((effects >> 10) & 0x03) == 0) && // is_noub(effects) + (((effects >> 3) & 0x03) == 0) && // is_effect_free(effects) + ((effects >> 6) & 0x01); // is_terminates(effects) +} + + // `jl_queue_for_serialization` adds items to `serialization_order` #define jl_queue_for_serialization(s, v) jl_queue_for_serialization_((s), (jl_value_t*)(v), 1, 0) static void jl_queue_for_serialization_(jl_serializer_state *s, jl_value_t *v, int recursive, int immediate) JL_GC_DISABLED; @@ -838,8 +848,24 @@ static void jl_insert_into_serialization_queue(jl_serializer_state *s, jl_value_ // TODO: if (ci in ci->defs->cache) record_field_change((jl_value_t**)&ci->next, NULL); } - if (jl_atomic_load_relaxed(&ci->inferred) && !is_relocatable_ci(&relocatable_ext_cis, ci)) - record_field_change((jl_value_t**)&ci->inferred, jl_nothing); + jl_value_t *inferred = jl_atomic_load_relaxed(&ci->inferred); + if (inferred && inferred != jl_nothing) { // disregard if there is nothing here to delete (e.g. builtins, unspecialized) + if (!is_relocatable_ci(&relocatable_ext_cis, ci)) + record_field_change((jl_value_t**)&ci->inferred, jl_nothing); + else if (jl_is_method(ci->def->def.method) && // don't delete toplevel code + ci->def->def.method->source) { // don't delete code from optimized opaque closures that can't be reconstructed (and builtins) + if (jl_atomic_load_relaxed(&ci->max_world) != ~(size_t)0 || // delete all code that cannot run + jl_atomic_load_relaxed(&ci->invoke) == jl_fptr_const_return) { // delete all code that just returns a constant + record_field_change((jl_value_t**)&ci->inferred, jl_nothing); + } + else if (native_functions && // don't delete any code if making a ji file + !effects_foldable(ci->ipo_purity_bits) && // don't delete code we may want for irinterp + jl_ir_inlining_cost(inferred) == UINT16_MAX) { // don't delete inlineable code + // delete the code now: if we thought it was worth keeping, it would have been converted to object code + record_field_change((jl_value_t**)&ci->inferred, jl_nothing); + } + } + } } if (immediate) // must be things that can be recursively handled, and valid as type parameters diff --git a/src/subtype.c b/src/subtype.c index 2017954392ba6..8c3049d445647 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -1600,6 +1600,42 @@ static int local_forall_exists_subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t return sub; } +static int equal_var(jl_tvar_t *v, jl_value_t *x, jl_stenv_t *e) +{ + assert(e->Loffset == 0); + // Theoretically bounds change would be merged for union inputs. + // But intersection is not happy as splitting helps to avoid circular env. + assert(!e->intersection || !jl_is_uniontype(x)); + jl_varbinding_t *vb = lookup(e, v); + if (e->intersection && vb != NULL && vb->lb == vb->ub && jl_is_typevar(vb->lb)) + return equal_var((jl_tvar_t *)vb->lb, x, e); + record_var_occurrence(vb, e, 2); + if (vb == NULL) + return e->ignore_free || ( + local_forall_exists_subtype(x, v->lb, e, 2, !jl_has_free_typevars(x)) && + local_forall_exists_subtype(v->ub, x, e, 0, 0)); + if (!vb->right) + return local_forall_exists_subtype(x, vb->lb, e, 2, !jl_has_free_typevars(x)) && + local_forall_exists_subtype(vb->ub, x, e, 0, 0); + if (vb->lb == x) + return var_lt(v, x, e, 0); + if (!subtype_ccheck(x, vb->ub, e)) + return 0; + jl_value_t *lb = simple_join(vb->lb, x); + JL_GC_PUSH1(&lb); + if (!e->intersection || !jl_is_typevar(lb) || !reachable_var(lb, v, e)) + vb->lb = lb; + JL_GC_POP(); + if (vb->ub == x) + return 1; + if (!subtype_ccheck(vb->lb, x, e)) + return 0; + // skip `simple_meet` here as we have proven `x <: vb->ub` + if (!e->intersection || !reachable_var(x, v, e)) + vb->ub = x; + return 1; +} + static int forall_exists_equal(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) { if (obviously_egal(x, y)) return 1; @@ -1630,6 +1666,12 @@ static int forall_exists_equal(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) } } + if (e->Loffset == 0 && jl_is_typevar(y) && jl_is_type(x) && (!e->intersection || !jl_is_uniontype(x))) { + // Fastpath for Type == TypeVar. + // Avoid duplicated `<:` check between adjacent `var_gt` and `var_lt` + return equal_var((jl_tvar_t *)y, x, e); + } + jl_saved_unionstate_t oldLunions; push_unionstate(&oldLunions, &e->Lunions); int sub = local_forall_exists_subtype(x, y, e, 2, -1); diff --git a/src/threading.c b/src/threading.c index dfc75b0af581e..d8b6b784c6108 100644 --- a/src/threading.c +++ b/src/threading.c @@ -411,11 +411,9 @@ JL_DLLEXPORT jl_gcframe_t **jl_adopt_thread(void) { // `jl_init_threadtls` puts us in a GC unsafe region, so ensure GC isn't running. // we can't use a normal safepoint because we don't have signal handlers yet. - // we also can't use jl_safepoint_wait_gc because that assumes we're in a task. jl_atomic_fetch_add(&jl_gc_disable_counter, 1); - while (jl_atomic_load_acquire(&jl_gc_running)) { - jl_cpu_pause(); - } + // pass NULL as a special token to indicate we are running on an unmanaged task + jl_safepoint_wait_gc(NULL); // this check is coupled with the one in `jl_safepoint_wait_gc`, where we observe if a // foreign thread has asked to disable the GC, guaranteeing the order of events. @@ -445,6 +443,29 @@ static void jl_delete_thread(void *value) JL_NOTSAFEPOINT_ENTER // prior unsafe-region (before we let it release the stack memory) (void)jl_gc_unsafe_enter(ptls); scheduler_delete_thread(ptls); + // need to clear pgcstack and eh, but we can clear everything now too + jl_task_t *ct = jl_atomic_load_relaxed(&ptls->current_task); + jl_task_frame_noreturn(ct); + if (jl_set_task_tid(ptls->root_task, ptls->tid)) { + // the system will probably free this stack memory soon + // so prevent any other thread from accessing it later + if (ct != ptls->root_task) + jl_task_frame_noreturn(ptls->root_task); + } + else { + // Uh oh. The user cleared the sticky bit so it started running + // elsewhere, then called pthread_exit on this thread from another + // Task, which will free the stack memory of that root task soon. This + // is not recoverable. Though we could just hang here, a fatal message + // is likely better. + jl_safe_printf("fatal: thread exited from wrong Task.\n"); + abort(); + } + ptls->previous_exception = NULL; + // allow the page root_task is on to be freed + ptls->root_task = NULL; + // park in safe-region from here on (this may run GC again) + (void)jl_gc_safe_enter(ptls); // try to free some state we do not need anymore #ifndef _OS_WINDOWS_ void *signal_stack = ptls->signal_stack; @@ -483,21 +504,7 @@ static void jl_delete_thread(void *value) JL_NOTSAFEPOINT_ENTER #else pthread_mutex_lock(&in_signal_lock); #endif - // need to clear pgcstack and eh, but we can clear everything now too - jl_task_frame_noreturn(jl_atomic_load_relaxed(&ptls->current_task)); - if (jl_set_task_tid(ptls->root_task, ptls->tid)) { - // the system will probably free this stack memory soon - // so prevent any other thread from accessing it later - jl_task_frame_noreturn(ptls->root_task); - } - else { - // Uh oh. The user cleared the sticky bit so it started running - // elsewhere, then called pthread_exit on this thread. This is not - // recoverable. Though we could just hang here, a fatal message is better. - jl_safe_printf("fatal: thread exited from wrong Task.\n"); - abort(); - } - jl_atomic_store_relaxed(&ptls->current_task, NULL); // dead + jl_atomic_store_relaxed(&ptls->current_task, NULL); // indicate dead // finally, release all of the locks we had grabbed #ifdef _OS_WINDOWS_ jl_unlock_profile_wr(); @@ -508,8 +515,6 @@ static void jl_delete_thread(void *value) JL_NOTSAFEPOINT_ENTER #else pthread_mutex_unlock(&in_signal_lock); #endif - // then park in safe-region - (void)jl_gc_safe_enter(ptls); } //// debugging hack: if we are exiting too fast for error message printing on threads, @@ -855,15 +860,20 @@ void _jl_mutex_wait(jl_task_t *self, jl_mutex_t *lock, int safepoint) jl_profile_lock_acquired(lock); return; } - if (safepoint) { - jl_gc_safepoint_(self->ptls); - } if (jl_running_under_rr(0)) { // when running under `rr`, use system mutexes rather than spin locking + int8_t gc_state; + if (safepoint) + gc_state = jl_gc_safe_enter(self->ptls); uv_mutex_lock(&tls_lock); if (jl_atomic_load_relaxed(&lock->owner)) uv_cond_wait(&cond, &tls_lock); uv_mutex_unlock(&tls_lock); + if (safepoint) + jl_gc_safe_leave(self->ptls, gc_state); + } + else if (safepoint) { + jl_gc_safepoint_(self->ptls); } jl_cpu_suspend(); owner = jl_atomic_load_relaxed(&lock->owner); diff --git a/stdlib/InteractiveUtils/src/InteractiveUtils.jl b/stdlib/InteractiveUtils/src/InteractiveUtils.jl index 519acfc8a2f33..661213567e0db 100644 --- a/stdlib/InteractiveUtils/src/InteractiveUtils.jl +++ b/stdlib/InteractiveUtils/src/InteractiveUtils.jl @@ -16,7 +16,7 @@ export apropos, edit, less, code_warntype, code_llvm, code_native, methodswith, import Base.Docs.apropos using Base: unwrap_unionall, rewrap_unionall, isdeprecated, Bottom, show_unquoted, summarysize, - signature_type, format_bytes + signature_type, format_bytes, isbindingresolved using Base.Libc using Markdown @@ -262,7 +262,7 @@ function _subtypes_in!(mods::Array, x::Type) m = pop!(mods) xt = xt::DataType for s in names(m, all = true) - if isdefined(m, s) && !isdeprecated(m, s) + if isbindingresolved(m, s) && !isdeprecated(m, s) && isdefined(m, s) t = getfield(m, s) dt = isa(t, UnionAll) ? unwrap_unionall(t) : t if isa(dt, DataType) diff --git a/stdlib/InteractiveUtils/test/runtests.jl b/stdlib/InteractiveUtils/test/runtests.jl index 346b111c785f7..72305ce66d308 100644 --- a/stdlib/InteractiveUtils/test/runtests.jl +++ b/stdlib/InteractiveUtils/test/runtests.jl @@ -728,3 +728,22 @@ end @testset "Docstrings" begin @test isempty(Docs.undocumented_names(InteractiveUtils)) end + +# issue https://github.com/JuliaIO/ImageMagick.jl/issues/235 +module OuterModule + module InternalModule + struct MyType + x::Int + end + + Base.@deprecate_binding MyOldType MyType + + export MyType + end + using .InternalModule + export MyType, MyOldType +end # module +@testset "Subtypes and deprecations" begin + using .OuterModule + @test_nowarn subtypes(Integer); +end diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 6dee5ed981ffa..300d42c186ab0 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = release-1.11 -PKG_SHA1 = 64bf95a4847898cf70de54d0c861c877ed5c1595 +PKG_SHA1 = 2eb8ae5b8f421fc77295f9cf382132d39e14d16f PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index 20d8bc44b854a..d2bc417fd9e7b 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -1025,7 +1025,7 @@ function complete_keyword_argument(partial, last_idx, context_module) kwargs_flag == 2 && return fail # one of the previous kwargs is invalid methods = Completion[] - complete_methods!(methods, funct, Any[Vararg{Any}], kwargs_ex, -1, kwargs_flag == 1) + complete_methods!(methods, funct, Any[Vararg{Any}], kwargs_ex, MAX_METHOD_COMPLETIONS, kwargs_flag == 1) # TODO: use args_ex instead of Any[Vararg{Any}] and only provide kwarg completion for # method calls compatible with the current arguments. diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index 4004e7289a305..b3711398c2e83 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -1198,7 +1198,7 @@ function print_test_results(ts::AbstractTestSet, depth_pad=0) duration_width = max(textwidth("Time"), textwidth(tc.duration)) # Calculate the alignment of the test result counts by # recursively walking the tree of test sets - align = max(get_alignment(ts, 0), textwidth("Test Summary:")) + align = max(get_alignment(ts, depth_pad), textwidth("Test Summary:")) # Print the outer test set header once printstyled(rpad("Test Summary:", align, " "), " |", " "; bold=true) if pass_width > 0 diff --git a/test/broadcast.jl b/test/broadcast.jl index 2ae3d96b2a709..f1c9d719b141b 100644 --- a/test/broadcast.jl +++ b/test/broadcast.jl @@ -905,6 +905,8 @@ let @test @inferred(Base.IteratorSize(Broadcast.broadcasted(+, (1,2,3), a1, zeros(3,3,3)))) === Base.HasShape{3}() + @test @inferred(Base.IteratorSize(Base.broadcasted(randn))) === Base.HasShape{0}() + # inference on nested bc = Base.broadcasted(+, AD1(randn(3)), AD1(randn(3))) bc_nest = Base.broadcasted(+, bc , bc) diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index eadbe719cc961..02bd1daf8b82e 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -5685,3 +5685,23 @@ t255751 = Array{Float32, 3} issue55882_nfields(x::Union{T,Nothing}) where T<:Number = nfields(x) @test Base.infer_return_type(issue55882_nfields) <: Int + +# JuliaLang/julia#56248 +@test Base.infer_return_type() do + TypeVar(:Issue56248, 1) +end === Union{} +@test Base.infer_return_type() do + TypeVar(:Issue56248, Any, 1) +end === Union{} + +function issue56387(nt::NamedTuple, field::Symbol=:a) + NT = typeof(nt) + names = fieldnames(NT) + types = fieldtypes(NT) + index = findfirst(==(field), names) + if index === nothing + throw(ArgumentError("Field $field not found")) + end + types[index] +end +@test Base.infer_return_type(issue56387, (typeof((;a=1)),)) == Type{Int} diff --git a/test/copy.jl b/test/copy.jl index 9faba839c98e0..b96e96ba2c313 100644 --- a/test/copy.jl +++ b/test/copy.jl @@ -251,6 +251,15 @@ end @test copyto!(s, String[]) == [1, 2] # No error end +@testset "circular reference arrays" begin + # issue 56775 + p = Any[nothing] + p[1] = p + p2 = deepcopy(p) + @test p2 === p2[1] + @test p2 !== p +end + @testset "deepcopy_internal arrays" begin @test (@inferred Base.deepcopy_internal(zeros(), IdDict())) == zeros() end diff --git a/test/dict.jl b/test/dict.jl index ca8a598de0b81..d33123237b0a1 100644 --- a/test/dict.jl +++ b/test/dict.jl @@ -787,6 +787,13 @@ end [v for (k, v) in d] == [d[x[1]] for (i, x) in enumerate(d)] end +@testset "consistency of dict iteration order (issue #56841)" begin + dict = Dict(randn() => randn() for _ = 1:100) + @test all(zip(dict, keys(dict), values(dict), pairs(dict))) do (d, k, v, p) + d == p && first(d) == first(p) == k && last(d) == last(p) == v + end +end + @testset "generators, similar" begin d = Dict(:a=>"a") # TODO: restore when 0.7 deprecation is removed diff --git a/test/math.jl b/test/math.jl index be134adb15d34..c48a0c7f56323 100644 --- a/test/math.jl +++ b/test/math.jl @@ -377,6 +377,10 @@ end end end +@testset "https://github.com/JuliaLang/julia/issues/56782" begin + @test isnan(exp(reinterpret(Float64, 0x7ffbb14880000000))) +end + @testset "test abstractarray trig functions" begin TAA = rand(2,2) TAA = (TAA + TAA')/2. diff --git a/test/meta.jl b/test/meta.jl index 5fb1ebc0d3647..2b235d3cc1b0d 100644 --- a/test/meta.jl +++ b/test/meta.jl @@ -276,6 +276,11 @@ ci = code_lowered(g, Tuple{Val{true}})[1] @test Meta.partially_inline!(copy(ci.code), Any[isdefined_globalref, 1], Tuple{typeof(isdefined_globalref), Int}, [], 0, 0, :propagate)[1] == Expr(:isdefined, GlobalRef(Base, :foo)) + withunreachable(s::String) = sin(s) + ci = code_lowered(withunreachable, Tuple{String})[1] + ci.code[end] = Core.ReturnNode() + @test Meta.partially_inline!(copy(ci.code), Any[withunreachable, "foo"], Tuple{typeof(withunreachable), String}, + [], 0, 0, :propagate)[end] == Core.ReturnNode() end @testset "Base.Meta docstrings" begin diff --git a/test/subarray.jl b/test/subarray.jl index d02da15dc3158..9cdddc1793ac1 100644 --- a/test/subarray.jl +++ b/test/subarray.jl @@ -1026,31 +1026,6 @@ catch err err isa ErrorException && startswith(err.msg, "syntax:") end - -@testset "avoid allocating in reindex" begin - a = reshape(1:16, 4, 4) - inds = ([2,3], [3,4]) - av = view(a, inds...) - av2 = view(av, 1, 1) - @test parentindices(av2) === (2,3) - av2 = view(av, 2:2, 2:2) - @test parentindices(av2) === (view(inds[1], 2:2), view(inds[2], 2:2)) - - inds = (reshape([eachindex(a);], size(a)),) - av = view(a, inds...) - av2 = view(av, 1, 1) - @test parentindices(av2) === (1,) - av2 = view(av, 2:2, 2:2) - @test parentindices(av2) === (view(inds[1], 2:2, 2:2),) - - inds = (reshape([eachindex(a);], size(a)..., 1),) - av = view(a, inds...) - av2 = view(av, 1, 1, 1) - @test parentindices(av2) === (1,) - av2 = view(av, 2:2, 2:2, 1:1) - @test parentindices(av2) === (view(inds[1], 2:2, 2:2, 1:1),) -end - @testset "isassigned" begin a = Vector{BigFloat}(undef, 5) a[2] = 0 diff --git a/test/subtype.jl b/test/subtype.jl index dfa1487eaa55d..ba7f86bb86a14 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -2730,3 +2730,19 @@ let S = Dict{V,V} where {V}, @test A <: typeintersect(S, T) @test A <: typeintersect(T, S) end + +#issue 56606 +let + A = Tuple{Val{1}} + B = Tuple{Val} + for _ in 1:30 + A = Tuple{Val{A}} + B = Tuple{Val{<:B}} + end + @test A <: B +end +@testintersect( + Val{Tuple{Int,S,T}} where {S<:Any,T<:Vector{Vector{Int}}}, + Val{Tuple{T,R,S}} where {T,R<:Vector{T},S<:Vector{R}}, + Val{Tuple{Int, Vector{Int}, T}} where T<:Vector{Vector{Int}}, +) diff --git a/test/syntax.jl b/test/syntax.jl index 1a2d61e821ef1..fe20189a56c81 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -3691,6 +3691,42 @@ begin end @test Foreign54607.bar == 9 +# Test that lowering doesn't accidentally put a `Module` in the Method name slot +let src = @Meta.lower let capture=1 + global foo_lower_block + foo_lower_block() = capture +end + code = src.args[1].code + for i = length(code):-1:1 + expr = code[i] + Meta.isexpr(expr, :method) || continue + @test isa(expr.args[1], Union{GlobalRef, Symbol}) + end +end + +let src = Meta.@lower let + try + try + return 1 + catch + end + finally + nothing + end +end + code = src.args[1].code + for stmt in code + if Meta.isexpr(stmt, :leave) && length(stmt.args) > 1 + # Expr(:leave, ...) should list the arguments to pop from + # inner-most scope to outer-most + @test issorted(Int[ + (arg::Core.SSAValue).id + for arg in stmt.args + ]; rev=true) + end + end +end + # Test that globals can be `using`'d even if they are not yet defined module UndefGlobal54954 global theglobal54954::Int