diff --git a/Makefile b/Makefile index 57d5cde328e02..ec13f23bbb2cf 100644 --- a/Makefile +++ b/Makefile @@ -377,6 +377,11 @@ endif cp -R -L $(JULIAHOME)/base/* $(DESTDIR)$(datarootdir)/julia/base cp -R -L $(JULIAHOME)/test/* $(DESTDIR)$(datarootdir)/julia/test cp -R -L $(build_datarootdir)/julia/* $(DESTDIR)$(datarootdir)/julia + + # Set .jl sources as read-only to match package directories + find $(DESTDIR)$(datarootdir)/julia/base -type f -name \*.jl -exec chmod 0444 '{}' \; + find $(DESTDIR)$(datarootdir)/julia/test -type f -name \*.jl -exec chmod 0444 '{}' \; + # Copy documentation cp -R -L $(BUILDROOT)/doc/_build/html $(DESTDIR)$(docdir)/ # Remove various files which should not be installed diff --git a/base/Base.jl b/base/Base.jl index 21c9a101758a0..0aa191206e3df 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -603,7 +603,7 @@ function __init__() init_active_project() append!(empty!(_sysimage_modules), keys(loaded_modules)) empty!(explicit_loaded_modules) - @assert isempty(loaded_precompiles) + empty!(loaded_precompiles) # If we load a packageimage when building the image this might not be empty for (mod, key) in module_keys loaded_precompiles[key => module_build_id(mod)] = mod end diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 2d281b487c437..ad70b973ab10b 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -3504,7 +3504,7 @@ function push!(a::AbstractVector{T}, item) where T itemT = item isa T ? item : convert(T, item)::T new_length = length(a) + 1 resize!(a, new_length) - a[new_length] = itemT + a[end] = itemT return a end @@ -3512,7 +3512,7 @@ end function push!(a::AbstractVector{Any}, @nospecialize x) new_length = length(a) + 1 resize!(a, new_length) - a[new_length] = x + a[end] = x return a end function push!(a::AbstractVector{Any}, @nospecialize x...) @@ -3520,8 +3520,9 @@ function push!(a::AbstractVector{Any}, @nospecialize x...) na = length(a) nx = length(x) resize!(a, na + nx) + e = lastindex(a) - nx for i = 1:nx - a[na+i] = x[i] + a[e+i] = x[i] end return a end diff --git a/base/compiler/typelimits.jl b/base/compiler/typelimits.jl index 318ac0b5c27e5..e5133f9aca0bf 100644 --- a/base/compiler/typelimits.jl +++ b/base/compiler/typelimits.jl @@ -815,6 +815,7 @@ end typenames[i] = Any.name simplify[i] = false types[j] = widen + typenames[j] = ijname break end end diff --git a/base/loading.jl b/base/loading.jl index 5614c3603e540..0262ace997a09 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -507,6 +507,8 @@ package root. To get the root directory of the package that implements the current module the form `pkgdir(@__MODULE__)` can be used. +If an extension module is given, the root of the parent package is returned. + ```julia-repl julia> pkgdir(Foo) "/path/to/Foo.jl" @@ -524,7 +526,19 @@ function pkgdir(m::Module, paths::String...) rootmodule = moduleroot(m) path = pathof(rootmodule) path === nothing && return nothing - return joinpath(dirname(dirname(path)), paths...) + original = path + path, base = splitdir(dirname(path)) + if base == "src" + # package source in `../src/Foo.jl` + elseif base == "ext" + # extension source in `../ext/FooExt.jl` + elseif basename(path) == "ext" + # extension source in `../ext/FooExt/FooExt.jl` + path = dirname(path) + else + error("Unexpected path structure for module source: $original") + end + return joinpath(path, paths...) end function get_pkgversion_from_path(path) @@ -1152,7 +1166,7 @@ const TIMING_IMPORTS = Threads.Atomic{Int}(0) # these return either the array of modules loaded from the path / content given # or an Exception that describes why it couldn't be loaded # and it reconnects the Base.Docs.META -function _include_from_serialized(pkg::PkgId, path::String, ocachepath::Union{Nothing, String}, depmods::Vector{Any}, ignore_native::Union{Nothing,Bool}=nothing) +function _include_from_serialized(pkg::PkgId, path::String, ocachepath::Union{Nothing, String}, depmods::Vector{Any}, ignore_native::Union{Nothing,Bool}=nothing; register::Bool=true) if isnothing(ignore_native) if JLOptions().code_coverage == 0 && JLOptions().malloc_log == 0 ignore_native = false @@ -1201,23 +1215,11 @@ function _include_from_serialized(pkg::PkgId, path::String, ocachepath::Union{No for M in restored M = M::Module if parentmodule(M) === M && PkgId(M) == pkg + register && register_root_module(M) if timing_imports - elapsed = round((time_ns() - t_before) / 1e6, digits = 1) + elapsed_time = time_ns() - t_before comp_time, recomp_time = cumulative_compile_time_ns() .- t_comp_before - print(lpad(elapsed, 9), " ms ") - parentid = get(EXT_PRIMED, pkg, nothing) - if parentid !== nothing - print(parentid.name, " → ") - end - print(pkg.name) - if comp_time > 0 - printstyled(" ", Ryu.writefixed(Float64(100 * comp_time / (elapsed * 1e6)), 2), "% compilation time", color = Base.info_color()) - end - if recomp_time > 0 - perc = Float64(100 * recomp_time / comp_time) - printstyled(" (", perc < 1 ? "<1" : Ryu.writefixed(perc, 0), "% recompilation)", color = Base.warn_color()) - end - println() + print_time_imports_report(M, elapsed_time, comp_time, recomp_time) end return M end @@ -1229,6 +1231,73 @@ function _include_from_serialized(pkg::PkgId, path::String, ocachepath::Union{No end end +# printing functions for @time_imports +# note that the time inputs are UInt64 on all platforms. Give default values here so that we don't have +# confusing UInt64 types in generate_precompile.jl +function print_time_imports_report( + mod::Module, + elapsed_time::UInt64=UInt64(1), + comp_time::UInt64=UInt64(1), + recomp_time::UInt64=UInt64(1) + ) + print(lpad(round(elapsed_time / 1e6, digits=1), 9), " ms ") + ext_parent = extension_parent_name(mod) + if ext_parent !== nothing + print(ext_parent::String, " → ") + end + print(string(mod)) + if comp_time > 0 + perc = Ryu.writefixed(Float64(100 * comp_time / (elapsed_time)), 2) + printstyled(" $perc% compilation time", color = Base.info_color()) + end + if recomp_time > 0 + perc = Float64(100 * recomp_time / comp_time) + perc_show = perc < 1 ? "<1" : Ryu.writefixed(perc, 0) + printstyled(" ($perc_show% recompilation)", color = Base.warn_color()) + end + println() +end +function print_time_imports_report_init( + mod::Module, i::Int=1, + elapsed_time::UInt64=UInt64(1), + comp_time::UInt64=UInt64(1), + recomp_time::UInt64=UInt64(1) + ) + connector = i > 1 ? "├" : "┌" + printstyled(" $connector ", color = :light_black) + print("$(round(elapsed_time / 1e6, digits=1)) ms $mod.__init__() ") + if comp_time > 0 + perc = Ryu.writefixed(Float64(100 * (comp_time) / elapsed_time), 2) + printstyled("$perc% compilation time", color = Base.info_color()) + end + if recomp_time > 0 + perc = Float64(100 * recomp_time / comp_time) + printstyled(" ($(perc < 1 ? "<1" : Ryu.writefixed(perc, 0))% recompilation)", color = Base.warn_color()) + end + println() +end + +# if M is an extension, return the string name of the parent. Otherwise return nothing +function extension_parent_name(M::Module) + rootmodule = moduleroot(M) + src_path = pathof(rootmodule) + src_path === nothing && return nothing + pkgdir_parts = splitpath(src_path) + ext_pos = findlast(==("ext"), pkgdir_parts) + if ext_pos !== nothing && ext_pos >= length(pkgdir_parts) - 2 + parent_package_root = joinpath(pkgdir_parts[1:ext_pos-1]...) + parent_package_project_file = locate_project_file(parent_package_root) + if parent_package_project_file isa String + d = parsed_toml(parent_package_project_file) + name = get(d, "name", nothing) + if name !== nothing + return name + end + end + end + return nothing +end + function register_restored_modules(sv::SimpleVector, pkg::PkgId, path::String) # This function is also used by PkgCacheInspector.jl restored = sv[1]::Vector{Any} @@ -1265,31 +1334,18 @@ function run_module_init(mod::Module, i::Int=1) # `i` informs ordering for the `@time_imports` report formatting if TIMING_IMPORTS[] == 0 ccall(:jl_init_restored_module, Cvoid, (Any,), mod) - else - if isdefined(mod, :__init__) - connector = i > 1 ? "├" : "┌" - printstyled(" $connector ", color = :light_black) - - elapsedtime = time_ns() - cumulative_compile_timing(true) - compile_elapsedtimes = cumulative_compile_time_ns() + elseif isdefined(mod, :__init__) + elapsed_time = time_ns() + cumulative_compile_timing(true) + compile_elapsedtimes = cumulative_compile_time_ns() - ccall(:jl_init_restored_module, Cvoid, (Any,), mod) + ccall(:jl_init_restored_module, Cvoid, (Any,), mod) - elapsedtime = (time_ns() - elapsedtime) / 1e6 - cumulative_compile_timing(false); - comp_time, recomp_time = (cumulative_compile_time_ns() .- compile_elapsedtimes) ./ 1e6 + elapsed_time = time_ns() - elapsed_time + cumulative_compile_timing(false); + comp_time, recomp_time = cumulative_compile_time_ns() .- compile_elapsedtimes - print("$(round(elapsedtime, digits=1)) ms $mod.__init__() ") - if comp_time > 0 - printstyled(Ryu.writefixed(Float64(100 * comp_time / elapsedtime), 2), "% compilation time", color = Base.info_color()) - end - if recomp_time > 0 - perc = Float64(100 * recomp_time / comp_time) - printstyled(" ($(perc < 1 ? "<1" : Ryu.writefixed(perc, 0))% recompilation)", color = Base.warn_color()) - end - println() - end + print_time_imports_report_init(mod, i, elapsed_time, comp_time, recomp_time) end end @@ -1403,7 +1459,7 @@ function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, Any} triggers = triggers::Union{String, Vector{String}} triggers isa String && (triggers = [triggers]) id = PkgId(uuid5(parent.uuid::UUID, ext), ext) - if id in keys(EXT_PRIMED) || haskey(Base.loaded_modules, id) + if haskey(EXT_PRIMED, id) || haskey(Base.loaded_modules, id) continue # extension is already primed or loaded, don't add it again end EXT_PRIMED[id] = parent @@ -1833,8 +1889,7 @@ function _tryrequire_from_serialized(pkg::PkgId, path::String, ocachepath::Union depmods[i] = dep end # then load the file - loaded = _include_from_serialized(pkg, path, ocachepath, depmods, ignore_native) - loaded isa Module && register_root_module(loaded) + loaded = _include_from_serialized(pkg, path, ocachepath, depmods, ignore_native; register = true) return loaded end @@ -1901,8 +1956,7 @@ end if dep === nothing try set_pkgorigin_version_path(modkey, modpath) - dep = _include_from_serialized(modkey, modcachepath, modocachepath, modstaledeps) - dep isa Module && stalecheck && register_root_module(dep) + dep = _include_from_serialized(modkey, modcachepath, modocachepath, modstaledeps; register = stalecheck) finally end_loading(modkey, dep) end @@ -1918,9 +1972,8 @@ end end restored = get(loaded_precompiles, pkg => newbuild_id, nothing) if !isa(restored, Module) - restored = _include_from_serialized(pkg, path_to_try, ocachefile, staledeps) + restored = _include_from_serialized(pkg, path_to_try, ocachefile, staledeps; register = stalecheck) end - isa(restored, Module) && stalecheck && register_root_module(restored) isa(restored, Module) && return restored @debug "Deserialization checks failed while attempting to load cache from $path_to_try" exception=restored @label check_next_path diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 519ac06e6e7ec..b6c93fa318d78 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -693,6 +693,8 @@ using .IteratorsMD end @inline checkindex(::Type{Bool}, inds::Tuple, I::CartesianIndex) = checkbounds_indices(Bool, inds, I.I) +@inline checkindex(::Type{Bool}, inds::Tuple, i::AbstractRange{<:CartesianIndex}) = + isempty(i) | (checkindex(Bool, inds, first(i)) & checkindex(Bool, inds, last(i))) # Indexing into Array with mixtures of Integers and CartesianIndices is # extremely performance-sensitive. While the abstract fallbacks support this, diff --git a/base/reducedim.jl b/base/reducedim.jl index 19d8f0a5af77c..2f51837a66050 100644 --- a/base/reducedim.jl +++ b/base/reducedim.jl @@ -261,8 +261,9 @@ function _mapreducedim!(f, op, R::AbstractArray, A::AbstractArrayOrBroadcasted) # use mapreduce_impl, which is probably better tuned to achieve higher performance nslices = div(length(A), lsiz) ibase = first(LinearIndices(A))-1 - for i = 1:nslices - @inbounds R[i] = op(R[i], mapreduce_impl(f, op, A, ibase+1, ibase+lsiz)) + for i in eachindex(R) + r = op(@inbounds(R[i]), mapreduce_impl(f, op, A, ibase+1, ibase+lsiz)) + @inbounds R[i] = r ibase += lsiz end return R diff --git a/base/strings/annotated.jl b/base/strings/annotated.jl index 69b04202edbf6..ef1ea28f42738 100644 --- a/base/strings/annotated.jl +++ b/base/strings/annotated.jl @@ -384,7 +384,7 @@ a vector of region–annotation tuples. In accordance with the semantics documented in [`AnnotatedString`](@ref), the order of annotations returned matches the order in which they were applied. -See also: `annotate!`. +See also: [`annotate!`](@ref). """ annotations(s::AnnotatedString) = s.annotations diff --git a/base/strings/io.jl b/base/strings/io.jl index 97cdedac3db78..4e413c0ebd78c 100644 --- a/base/strings/io.jl +++ b/base/strings/io.jl @@ -365,7 +365,8 @@ function _join_preserve_annotations(iterator, args...) # in nature, we extract an `AnnotatedString`, otherwise we just extract # a plain `String` from `io`. if isconcretetype(et) || !isempty(io.annotations) - read(seekstart(io), AnnotatedString{String}) + seekstart(io) + read(io, AnnotatedString{String}) else String(take!(io.io)) end diff --git a/base/strings/unicode.jl b/base/strings/unicode.jl index a3b06063b98ac..2e142be901b0b 100644 --- a/base/strings/unicode.jl +++ b/base/strings/unicode.jl @@ -5,7 +5,8 @@ module Unicode import Base: show, ==, hash, string, Symbol, isless, length, eltype, convert, isvalid, ismalformed, isoverlong, iterate, - AnnotatedString, AnnotatedChar, annotated_chartransform + AnnotatedString, AnnotatedChar, annotated_chartransform, + annotations # whether codepoints are valid Unicode scalar values, i.e. 0-0xd7ff, 0xe000-0x10ffff diff --git a/contrib/generate_precompile.jl b/contrib/generate_precompile.jl index 92dde676244e4..e4eeeed577686 100644 --- a/contrib/generate_precompile.jl +++ b/contrib/generate_precompile.jl @@ -41,6 +41,8 @@ precompile(Base.__require_prelocked, (Base.PkgId, Nothing)) precompile(Base._require, (Base.PkgId, Nothing)) precompile(Base.indexed_iterate, (Pair{Symbol, Union{Nothing, String}}, Int)) precompile(Base.indexed_iterate, (Pair{Symbol, Union{Nothing, String}}, Int, Int)) +precompile(Tuple{typeof(Base.Threads.atomic_add!), Base.Threads.Atomic{Int}, Int}) +precompile(Tuple{typeof(Base.Threads.atomic_sub!), Base.Threads.Atomic{Int}, Int}) # Pkg loading precompile(Tuple{typeof(Base.Filesystem.normpath), String, String, Vararg{String}}) @@ -163,6 +165,8 @@ for match = Base._methods(+, (Int, Int), -1, Base.get_world_counter()) 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) @@ -174,6 +178,11 @@ for match = Base._methods(+, (Int, Int), -1, Base.get_world_counter()) # interactive statup uses this write(IOBuffer(), "") + # not critical, but helps hide unrelated compilation from @time when using --trace-compile + foo() = rand(2,2) * rand(2,2) + @time foo() + @time foo() + break # only actually need to do this once end """ diff --git a/deps/checksums/Downloads-1061ecc377a053fce0df94e1a19e5260f7c030f5.tar.gz/md5 b/deps/checksums/Downloads-1061ecc377a053fce0df94e1a19e5260f7c030f5.tar.gz/md5 new file mode 100644 index 0000000000000..f42bbedb6d415 --- /dev/null +++ b/deps/checksums/Downloads-1061ecc377a053fce0df94e1a19e5260f7c030f5.tar.gz/md5 @@ -0,0 +1 @@ +70878dd96911d6960537dfee2a820d98 diff --git a/deps/checksums/Downloads-1061ecc377a053fce0df94e1a19e5260f7c030f5.tar.gz/sha512 b/deps/checksums/Downloads-1061ecc377a053fce0df94e1a19e5260f7c030f5.tar.gz/sha512 new file mode 100644 index 0000000000000..83164cad9a89d --- /dev/null +++ b/deps/checksums/Downloads-1061ecc377a053fce0df94e1a19e5260f7c030f5.tar.gz/sha512 @@ -0,0 +1 @@ +87d2bdc6c85cbbce5302aab8ffe92fc542c9c71a396844fcc04c0416be059b00298b4816ab5e5491dbf865660a3a6152f1c245875a1ec75fb49b4c7ba0d303d8 diff --git a/deps/checksums/Downloads-a9d274ff6588cc5dbfa90e908ee34c2408bab84a.tar.gz/md5 b/deps/checksums/Downloads-a9d274ff6588cc5dbfa90e908ee34c2408bab84a.tar.gz/md5 deleted file mode 100644 index fc3bce951cafb..0000000000000 --- a/deps/checksums/Downloads-a9d274ff6588cc5dbfa90e908ee34c2408bab84a.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -97bb33510fadec7f4cc4c718c739e9a0 diff --git a/deps/checksums/Downloads-a9d274ff6588cc5dbfa90e908ee34c2408bab84a.tar.gz/sha512 b/deps/checksums/Downloads-a9d274ff6588cc5dbfa90e908ee34c2408bab84a.tar.gz/sha512 deleted file mode 100644 index bf2821e8252b0..0000000000000 --- a/deps/checksums/Downloads-a9d274ff6588cc5dbfa90e908ee34c2408bab84a.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -a362aaf762f42deebb8632a7a7980cd22b2777e8c4dc629e418580269e24a64217ad846d61acad70438cfdc190e47ba2ff7716edd4e04d8d10c1d765efce604d diff --git a/deps/checksums/Pkg-2ff691035e9b2780cbd2fcb8dd30b640d85edde2.tar.gz/md5 b/deps/checksums/Pkg-2ff691035e9b2780cbd2fcb8dd30b640d85edde2.tar.gz/md5 deleted file mode 100644 index fe1a6a5d418b4..0000000000000 --- a/deps/checksums/Pkg-2ff691035e9b2780cbd2fcb8dd30b640d85edde2.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -6f6793bcb797bfd2c48f52c631ce9479 diff --git a/deps/checksums/Pkg-2ff691035e9b2780cbd2fcb8dd30b640d85edde2.tar.gz/sha512 b/deps/checksums/Pkg-2ff691035e9b2780cbd2fcb8dd30b640d85edde2.tar.gz/sha512 deleted file mode 100644 index ea7ace0f5e812..0000000000000 --- a/deps/checksums/Pkg-2ff691035e9b2780cbd2fcb8dd30b640d85edde2.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -70a9e47694082ab3f999891e03a932d1d43f9a700de1c7943d943f11c98d0893dafa9ed19f585dfe1af9aa053c5db1efde4af55c26b824632afa057ecb97f07a diff --git a/deps/checksums/Pkg-69938284d6804dd30a24577397f52dfdedbd37e1.tar.gz/md5 b/deps/checksums/Pkg-69938284d6804dd30a24577397f52dfdedbd37e1.tar.gz/md5 new file mode 100644 index 0000000000000..12ef870b31933 --- /dev/null +++ b/deps/checksums/Pkg-69938284d6804dd30a24577397f52dfdedbd37e1.tar.gz/md5 @@ -0,0 +1 @@ +248ce4c4b85394431e71b6f555f82216 diff --git a/deps/checksums/Pkg-69938284d6804dd30a24577397f52dfdedbd37e1.tar.gz/sha512 b/deps/checksums/Pkg-69938284d6804dd30a24577397f52dfdedbd37e1.tar.gz/sha512 new file mode 100644 index 0000000000000..b51345f090447 --- /dev/null +++ b/deps/checksums/Pkg-69938284d6804dd30a24577397f52dfdedbd37e1.tar.gz/sha512 @@ -0,0 +1 @@ +84f193d72062199f2791ba7f7c2b6eb547e1a97569ae20cbb3557bc291715dd0cf55b2e121c4829b4572929e97255fd53b9210a168a7fde36f09ae6cf76c7f40 diff --git a/src/gc-stacks.c b/src/gc-stacks.c index 3f40e2fc15d81..82094035349b3 100644 --- a/src/gc-stacks.c +++ b/src/gc-stacks.c @@ -22,22 +22,13 @@ // number of stacks to always keep available per pool #define MIN_STACK_MAPPINGS_PER_POOL 5 -#if defined(_OS_WINDOWS_) || (!defined(_OS_OPENBSD_) && !defined(JL_HAVE_UCONTEXT) && !defined(JL_HAVE_SIGALTSTACK)) -#define JL_USE_GUARD_PAGE 1 const size_t jl_guard_size = (4096 * 8); -#else -const size_t jl_guard_size = 0; -#endif - static _Atomic(uint32_t) num_stack_mappings = 0; #ifdef _OS_WINDOWS_ #define MAP_FAILED NULL static void *malloc_stack(size_t bufsz) JL_NOTSAFEPOINT { - size_t guard_size = LLT_ALIGN(jl_guard_size, jl_page_size); - bufsz += guard_size; - void *stk = VirtualAlloc(NULL, bufsz, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (stk == NULL) return MAP_FAILED; @@ -46,7 +37,6 @@ static void *malloc_stack(size_t bufsz) JL_NOTSAFEPOINT VirtualFree(stk, 0, MEM_RELEASE); return MAP_FAILED; } - stk = (char *)stk + guard_size; jl_atomic_fetch_add(&num_stack_mappings, 1); return stk; @@ -55,12 +45,6 @@ static void *malloc_stack(size_t bufsz) JL_NOTSAFEPOINT static void free_stack(void *stkbuf, size_t bufsz) { -#ifdef JL_USE_GUARD_PAGE - size_t guard_size = LLT_ALIGN(jl_guard_size, jl_page_size); - bufsz += guard_size; - stkbuf = (char *)stkbuf - guard_size; -#endif - VirtualFree(stkbuf, 0, MEM_RELEASE); jl_atomic_fetch_add(&num_stack_mappings, -1); } @@ -69,22 +53,16 @@ static void free_stack(void *stkbuf, size_t bufsz) static void *malloc_stack(size_t bufsz) JL_NOTSAFEPOINT { -#ifdef JL_USE_GUARD_PAGE - size_t guard_size = LLT_ALIGN(jl_guard_size, jl_page_size); - bufsz += guard_size; -#endif - void* stk = mmap(0, bufsz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (stk == MAP_FAILED) return MAP_FAILED; -#ifdef JL_USE_GUARD_PAGE +#if !defined(JL_HAVE_UCONTEXT) && !defined(JL_HAVE_SIGALTSTACK) // set up a guard page to detect stack overflow if (mprotect(stk, jl_guard_size, PROT_NONE) == -1) { munmap(stk, bufsz); return MAP_FAILED; } - stk = (char *)stk + guard_size; #endif jl_atomic_fetch_add(&num_stack_mappings, 1); return stk; @@ -92,12 +70,6 @@ static void *malloc_stack(size_t bufsz) JL_NOTSAFEPOINT static void free_stack(void *stkbuf, size_t bufsz) { -#ifdef JL_USE_GUARD_PAGE - size_t guard_size = LLT_ALIGN(jl_guard_size, jl_page_size); - bufsz += guard_size; - stkbuf = (char *)stkbuf - guard_size; -#endif - munmap(stkbuf, bufsz); jl_atomic_fetch_add(&num_stack_mappings, -1); } diff --git a/src/init.c b/src/init.c index 2c1ad618948f8..a5c9a6b19f94d 100644 --- a/src/init.c +++ b/src/init.c @@ -883,8 +883,8 @@ static NOINLINE void _finish_julia_init(JL_IMAGE_SEARCH rel, jl_ptls_t ptls, jl_ jl_n_markthreads = 0; jl_n_sweepthreads = 0; jl_n_gcthreads = 0; - jl_n_threads_per_pool[0] = 1; - jl_n_threads_per_pool[1] = 0; + jl_n_threads_per_pool[0] = 0; // Interactive threadpool + jl_n_threads_per_pool[1] = 1; // Default threadpool } else { post_image_load_hooks(); } diff --git a/src/signals-unix.c b/src/signals-unix.c index 8b79e11863e1f..5732fd1e9c91d 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -292,6 +292,8 @@ int exc_reg_is_write_fault(uintptr_t esr) { #if defined(HAVE_MACH) #include "signals-mach.c" #else +#include +#include int jl_lock_stackwalk(void) { @@ -404,17 +406,13 @@ JL_NO_ASAN static void segv_handler(int sig, siginfo_t *info, void *context) } } -#if !defined(JL_DISABLE_LIBUNWIND) -static bt_context_t *signal_context; -pthread_mutex_t in_signal_lock; -static pthread_cond_t exit_signal_cond; -static pthread_cond_t signal_caught_cond; +pthread_mutex_t in_signal_lock; // shared with jl_delete_thread +static bt_context_t *signal_context; // protected by in_signal_lock +static int exit_signal_cond = -1; +static int signal_caught_cond = -1; int jl_thread_suspend_and_get_state(int tid, int timeout, bt_context_t *ctx) { - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += timeout; pthread_mutex_lock(&in_signal_lock); jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[tid]; jl_task_t *ct2 = ptls2 ? jl_atomic_load_relaxed(&ptls2->current_task) : NULL; @@ -423,48 +421,51 @@ int jl_thread_suspend_and_get_state(int tid, int timeout, bt_context_t *ctx) pthread_mutex_unlock(&in_signal_lock); return 0; } - jl_atomic_store_release(&ptls2->signal_request, 1); - pthread_kill(ptls2->system_id, SIGUSR2); - // wait for thread to acknowledge - int err = pthread_cond_timedwait(&signal_caught_cond, &in_signal_lock, &ts); - if (err == ETIMEDOUT) { - sig_atomic_t request = 1; + sig_atomic_t request = 0; + if (!jl_atomic_cmpswap(&ptls2->signal_request, &request, 1)) { + // something is wrong, or there is already a usr2 in flight elsewhere + pthread_mutex_unlock(&in_signal_lock); + return 0; + } + request = 1; + int err = pthread_kill(ptls2->system_id, SIGUSR2); + // wait for thread to acknowledge or timeout + struct pollfd event = {signal_caught_cond, POLLIN, 0}; + if (err == 0) { + do { + err = poll(&event, 1, timeout * 1000); + } while (err == -1 && errno == EINTR); + } + if ((event.revents & POLLIN) == 0) { + // not ready after timeout: try to cancel this request if (jl_atomic_cmpswap(&ptls2->signal_request, &request, 0)) { pthread_mutex_unlock(&in_signal_lock); return 0; } - // Request is either now 0 (meaning the other thread is waiting for - // exit_signal_cond already), - // Or it is now -1 (meaning the other thread - // is waiting for in_signal_lock, and we need to release that lock - // here for a bit, until the other thread has a chance to get to the - // exit_signal_cond) - if (request == -1) { - err = pthread_cond_wait(&signal_caught_cond, &in_signal_lock); - assert(!err); - } } + eventfd_t got; + do { + err = read(signal_caught_cond, &got, sizeof(eventfd_t)); + } while (err == -1 && errno == EINTR); + if (err != sizeof(eventfd_t)) abort(); + assert(got == 1); (void) got; // Now the other thread is waiting on exit_signal_cond (verify that here by // checking it is 0, and add an acquire barrier for good measure) - int request = jl_atomic_load_acquire(&ptls2->signal_request); + request = jl_atomic_load_acquire(&ptls2->signal_request); assert(request == 0); (void) request; - jl_atomic_store_release(&ptls2->signal_request, 1); // prepare to resume normally + jl_atomic_store_release(&ptls2->signal_request, 4); // prepare to resume normally, but later code may change this *ctx = *signal_context; return 1; } void jl_thread_resume(int tid) { - jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[tid]; - pthread_cond_broadcast(&exit_signal_cond); - pthread_cond_wait(&signal_caught_cond, &in_signal_lock); // wait for thread to acknowledge (so that signal_request doesn't get mixed up) - // The other thread is waiting to leave exit_signal_cond (verify that here by - // checking it is 0, and add an acquire barrier for good measure) - int request = jl_atomic_load_acquire(&ptls2->signal_request); - assert(request == 0); (void) request; + int err; + eventfd_t got = 1; + err = write(exit_signal_cond, &got, sizeof(eventfd_t)); + if (err != sizeof(eventfd_t)) abort(); pthread_mutex_unlock(&in_signal_lock); } -#endif // Throw jl_interrupt_exception if the master thread is in a signal async region // or if SIGINT happens too often. @@ -473,9 +474,11 @@ static void jl_try_deliver_sigint(void) jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[0]; jl_safepoint_enable_sigint(); jl_wake_libuv(); + pthread_mutex_lock(&in_signal_lock); jl_atomic_store_release(&ptls2->signal_request, 2); // This also makes sure `sleep` is aborted. pthread_kill(ptls2->system_id, SIGUSR2); + pthread_mutex_unlock(&in_signal_lock); } // Write only by signal handling thread, read only by main thread @@ -508,12 +511,12 @@ static void jl_exit_thread0(int signo, jl_bt_element_t *bt_data, size_t bt_size) } // request: -// -1: beginning processing [invalid outside here] // 0: nothing [not from here] -// 1: get state +// 1: get state & wait for request // 2: throw sigint if `!defer_signal && io_wait` or if force throw threshold // is reached // 3: raise `thread0_exit_signo` and try to exit +// 4: no-op void usr2_handler(int sig, siginfo_t *info, void *ctx) { jl_task_t *ct = jl_get_current_task(); @@ -524,25 +527,21 @@ void usr2_handler(int sig, siginfo_t *info, void *ctx) return; int errno_save = errno; // acknowledge that we saw the signal_request - sig_atomic_t request = jl_atomic_exchange(&ptls->signal_request, -1); -#if !defined(JL_DISABLE_LIBUNWIND) + sig_atomic_t request = jl_atomic_exchange(&ptls->signal_request, 0); if (request == 1) { - pthread_mutex_lock(&in_signal_lock); signal_context = jl_to_bt_context(ctx); - // acknowledge that we set the signal_caught_cond broadcast + int err; + eventfd_t got = 1; + err = write(signal_caught_cond, &got, sizeof(eventfd_t)); + if (err != sizeof(eventfd_t)) abort(); + do { + err = read(exit_signal_cond, &got, sizeof(eventfd_t)); + } while (err == -1 && errno == EINTR); + if (err != sizeof(eventfd_t)) abort(); + assert(got == 1); request = jl_atomic_exchange(&ptls->signal_request, 0); - assert(request == -1); (void) request; - pthread_cond_broadcast(&signal_caught_cond); - pthread_cond_wait(&exit_signal_cond, &in_signal_lock); - request = jl_atomic_exchange(&ptls->signal_request, 0); - assert(request == 1 || request == 3); - // acknowledge that we got the resume signal - pthread_cond_broadcast(&signal_caught_cond); - pthread_mutex_unlock(&in_signal_lock); + assert(request == 2 || request == 3 || request == 4); } - else -#endif - jl_atomic_exchange(&ptls->signal_request, 0); // returns -1 if (request == 2) { int force = jl_check_force_sigint(); if (force || (!ptls->defer_signal && ptls->io_wait)) { @@ -987,10 +986,12 @@ void restore_signals(void) jl_sigsetset(&sset); pthread_sigmask(SIG_SETMASK, &sset, 0); -#if !defined(HAVE_MACH) && !defined(JL_DISABLE_LIBUNWIND) +#if !defined(HAVE_MACH) + exit_signal_cond = eventfd(0, EFD_CLOEXEC); + signal_caught_cond = eventfd(0, EFD_CLOEXEC); if (pthread_mutex_init(&in_signal_lock, NULL) != 0 || - pthread_cond_init(&exit_signal_cond, NULL) != 0 || - pthread_cond_init(&signal_caught_cond, NULL) != 0) { + exit_signal_cond == -1 || + signal_caught_cond == -1) { jl_error("SIGUSR pthread init failed"); } #endif diff --git a/stdlib/Downloads.version b/stdlib/Downloads.version index 7805348a4b2f5..cb041d86d7f66 100644 --- a/stdlib/Downloads.version +++ b/stdlib/Downloads.version @@ -1,4 +1,4 @@ DOWNLOADS_BRANCH = master -DOWNLOADS_SHA1 = a9d274ff6588cc5dbfa90e908ee34c2408bab84a +DOWNLOADS_SHA1 = 1061ecc377a053fce0df94e1a19e5260f7c030f5 DOWNLOADS_GIT_URL := https://github.com/JuliaLang/Downloads.jl.git DOWNLOADS_TAR_URL = https://api.github.com/repos/JuliaLang/Downloads.jl/tarball/$1 diff --git a/stdlib/LinearAlgebra/src/diagonal.jl b/stdlib/LinearAlgebra/src/diagonal.jl index d27da450205f7..830332db0dbb1 100644 --- a/stdlib/LinearAlgebra/src/diagonal.jl +++ b/stdlib/LinearAlgebra/src/diagonal.jl @@ -250,21 +250,6 @@ end (+)(Da::Diagonal, Db::Diagonal) = Diagonal(Da.diag + Db.diag) (-)(Da::Diagonal, Db::Diagonal) = Diagonal(Da.diag - Db.diag) -for f in (:+, :-) - @eval function $f(D::Diagonal{<:Number}, S::Symmetric) - return Symmetric($f(D, S.data), sym_uplo(S.uplo)) - end - @eval function $f(S::Symmetric, D::Diagonal{<:Number}) - return Symmetric($f(S.data, D), sym_uplo(S.uplo)) - end - @eval function $f(D::Diagonal{<:Real}, H::Hermitian) - return Hermitian($f(D, H.data), sym_uplo(H.uplo)) - end - @eval function $f(H::Hermitian, D::Diagonal{<:Real}) - return Hermitian($f(H.data, D), sym_uplo(H.uplo)) - end -end - (*)(x::Number, D::Diagonal) = Diagonal(x * D.diag) (*)(D::Diagonal, x::Number) = Diagonal(D.diag * x) (/)(D::Diagonal, x::Number) = Diagonal(D.diag / x) @@ -991,3 +976,6 @@ end function Base.muladd(A::Diagonal, B::Diagonal, z::Diagonal) Diagonal(A.diag .* B.diag .+ z.diag) end + +uppertriangular(D::Diagonal) = D +lowertriangular(D::Diagonal) = D diff --git a/stdlib/LinearAlgebra/src/special.jl b/stdlib/LinearAlgebra/src/special.jl index 1363708fb515f..2a3b6bf2a8e00 100644 --- a/stdlib/LinearAlgebra/src/special.jl +++ b/stdlib/LinearAlgebra/src/special.jl @@ -264,6 +264,25 @@ function (-)(A::UniformScaling, B::Diagonal) Diagonal(Ref(A) .- B.diag) end +for f in (:+, :-) + @eval function $f(D::Diagonal{<:Number}, S::Symmetric) + uplo = sym_uplo(S.uplo) + return Symmetric(parentof_applytri($f, Symmetric(D, uplo), S), uplo) + end + @eval function $f(S::Symmetric, D::Diagonal{<:Number}) + uplo = sym_uplo(S.uplo) + return Symmetric(parentof_applytri($f, S, Symmetric(D, uplo)), uplo) + end + @eval function $f(D::Diagonal{<:Real}, H::Hermitian) + uplo = sym_uplo(H.uplo) + return Hermitian(parentof_applytri($f, Hermitian(D, uplo), H), uplo) + end + @eval function $f(H::Hermitian, D::Diagonal{<:Real}) + uplo = sym_uplo(H.uplo) + return Hermitian(parentof_applytri($f, H, Hermitian(D, uplo)), uplo) + end +end + ## Diagonal construction from UniformScaling Diagonal{T}(s::UniformScaling, m::Integer) where {T} = Diagonal{T}(fill(T(s.λ), m)) Diagonal(s::UniformScaling, m::Integer) = Diagonal{eltype(s)}(s, m) diff --git a/stdlib/LinearAlgebra/src/symmetric.jl b/stdlib/LinearAlgebra/src/symmetric.jl index 6f778629b51b7..8cc07566c109e 100644 --- a/stdlib/LinearAlgebra/src/symmetric.jl +++ b/stdlib/LinearAlgebra/src/symmetric.jl @@ -277,21 +277,21 @@ diag(A::Hermitian) = hermitian.(diag(parent(A)), sym_uplo(A.uplo)) function applytri(f, A::HermOrSym) if A.uplo == 'U' - f(UpperTriangular(A.data)) + f(uppertriangular(A.data)) else - f(LowerTriangular(A.data)) + f(lowertriangular(A.data)) end end function applytri(f, A::HermOrSym, B::HermOrSym) if A.uplo == B.uplo == 'U' - f(UpperTriangular(A.data), UpperTriangular(B.data)) + f(uppertriangular(A.data), uppertriangular(B.data)) elseif A.uplo == B.uplo == 'L' - f(LowerTriangular(A.data), LowerTriangular(B.data)) + f(lowertriangular(A.data), lowertriangular(B.data)) elseif A.uplo == 'U' - f(UpperTriangular(A.data), UpperTriangular(_conjugation(B)(B.data))) + f(uppertriangular(A.data), uppertriangular(_conjugation(B)(B.data))) else # A.uplo == 'L' - f(UpperTriangular(_conjugation(A)(A.data)), UpperTriangular(B.data)) + f(uppertriangular(_conjugation(A)(A.data)), uppertriangular(B.data)) end end parentof_applytri(f, args...) = applytri(parent ∘ f, args...) diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index 0cd5a49a0956d..fb9f6b2df9121 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -153,6 +153,12 @@ const UpperOrUnitUpperTriangular{T,S} = Union{UpperTriangular{T,S}, UnitUpperTri const LowerOrUnitLowerTriangular{T,S} = Union{LowerTriangular{T,S}, UnitLowerTriangular{T,S}} const UpperOrLowerTriangular{T,S} = Union{UpperOrUnitUpperTriangular{T,S}, LowerOrUnitLowerTriangular{T,S}} +uppertriangular(M) = UpperTriangular(M) +lowertriangular(M) = LowerTriangular(M) + +uppertriangular(U::UpperOrUnitUpperTriangular) = U +lowertriangular(U::LowerOrUnitLowerTriangular) = U + imag(A::UpperTriangular) = UpperTriangular(imag(A.data)) imag(A::LowerTriangular) = LowerTriangular(imag(A.data)) imag(A::UpperTriangular{<:Any,<:StridedMaybeAdjOrTransMat}) = imag.(A) diff --git a/stdlib/LinearAlgebra/test/diagonal.jl b/stdlib/LinearAlgebra/test/diagonal.jl index c20c63b5b3477..7049dd784faa8 100644 --- a/stdlib/LinearAlgebra/test/diagonal.jl +++ b/stdlib/LinearAlgebra/test/diagonal.jl @@ -1277,6 +1277,12 @@ end @test c == Diagonal([2,2,2,2]) end +@testset "uppertriangular/lowertriangular" begin + D = Diagonal([1,2]) + @test LinearAlgebra.uppertriangular(D) === D + @test LinearAlgebra.lowertriangular(D) === D +end + @testset "mul/div with an adjoint vector" begin A = [1.0;;] x = [1.0] @@ -1312,4 +1318,9 @@ end end end +@testset "bounds-check with CartesianIndex ranges" begin + D = Diagonal(1:typemax(Int)) + @test checkbounds(Bool, D, diagind(D, IndexCartesian())) +end + end # module TestDiagonal diff --git a/stdlib/LinearAlgebra/test/special.jl b/stdlib/LinearAlgebra/test/special.jl index 7e96af369e310..148ccd85efeb1 100644 --- a/stdlib/LinearAlgebra/test/special.jl +++ b/stdlib/LinearAlgebra/test/special.jl @@ -536,4 +536,17 @@ end @test v * S isa Matrix end +@testset "Partly filled Hermitian and Diagonal algebra" begin + D = Diagonal([1,2]) + for S in (Symmetric, Hermitian), uplo in (:U, :L) + M = Matrix{BigInt}(undef, 2, 2) + M[1,1] = M[2,2] = M[1+(uplo == :L), 1 + (uplo == :U)] = 3 + H = S(M, uplo) + HM = Matrix(H) + @test H + D == D + H == HM + D + @test H - D == HM - D + @test D - H == D - HM + end +end + end # module TestSpecial diff --git a/stdlib/LinearAlgebra/test/symmetric.jl b/stdlib/LinearAlgebra/test/symmetric.jl index 23556c6548742..25522042dcf2b 100644 --- a/stdlib/LinearAlgebra/test/symmetric.jl +++ b/stdlib/LinearAlgebra/test/symmetric.jl @@ -507,6 +507,31 @@ end @test Su - Sl == -(Sl - Su) == MSu - MSl end end + @testset "non-strided" begin + @testset "diagonal" begin + for ST1 in (Symmetric, Hermitian), uplo1 in (:L, :U) + m = ST1(Matrix{BigFloat}(undef,2,2), uplo1) + m.data[1,1] = 1 + m.data[2,2] = 3 + m.data[1+(uplo1==:L), 1+(uplo1==:U)] = 2 + A = Array(m) + for ST2 in (Symmetric, Hermitian), uplo2 in (:L, :U) + id = ST2(I(2), uplo2) + @test m + id == id + m == A + id + end + end + end + @testset "unit triangular" begin + for ST1 in (Symmetric, Hermitian), uplo1 in (:L, :U) + H1 = ST1(UnitUpperTriangular(big.(rand(Int8,4,4))), uplo1) + M1 = Matrix(H1) + for ST2 in (Symmetric, Hermitian), uplo2 in (:L, :U) + H2 = ST2(UnitUpperTriangular(big.(rand(Int8,4,4))), uplo2) + @test H1 + H2 == M1 + Matrix(H2) + end + end + end + end end # bug identified in PR #52318: dot products of quaternionic Hermitian matrices, diff --git a/stdlib/LinearAlgebra/test/triangular.jl b/stdlib/LinearAlgebra/test/triangular.jl index 98334639c11e9..f37bf05650452 100644 --- a/stdlib/LinearAlgebra/test/triangular.jl +++ b/stdlib/LinearAlgebra/test/triangular.jl @@ -996,6 +996,14 @@ end end end +@testset "uppertriangular/lowertriangular" begin + M = rand(2,2) + @test LinearAlgebra.uppertriangular(M) === UpperTriangular(M) + @test LinearAlgebra.lowertriangular(M) === LowerTriangular(M) + @test LinearAlgebra.uppertriangular(UnitUpperTriangular(M)) === UnitUpperTriangular(M) + @test LinearAlgebra.lowertriangular(UnitLowerTriangular(M)) === UnitLowerTriangular(M) +end + @testset "arithmetic with partly uninitialized matrices" begin @testset "$(typeof(A))" for A in (Matrix{BigFloat}(undef,2,2), Matrix{Complex{BigFloat}}(undef,2,2)') A[2,1] = eltype(A) <: Complex ? 4 + 3im : 4 diff --git a/stdlib/Markdown/src/Markdown.jl b/stdlib/Markdown/src/Markdown.jl index 93d8dbc39fc59..e8c64deb3d593 100644 --- a/stdlib/Markdown/src/Markdown.jl +++ b/stdlib/Markdown/src/Markdown.jl @@ -98,4 +98,25 @@ import Base.Docs: catdoc catdoc(md::MD...) = MD(md...) +if Base.generating_output() + # workload to reduce latency + md""" + # H1 + ## H2 + ### H3 + **bold text** + *italicized text* + > blockquote + 1. First item + 2. Second item + 3. Third item + - First item + - Second item + - Third item + `code` + Horizontal Rule + --- + """ +end + end diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 9c627070566a9..5729fc9f7c69d 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = release-1.11 -PKG_SHA1 = 2ff691035e9b2780cbd2fcb8dd30b640d85edde2 +PKG_SHA1 = 69938284d6804dd30a24577397f52dfdedbd37e1 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/test/abstractarray.jl b/test/abstractarray.jl index 88cffbcf2947d..8244d3fc791f5 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -1424,14 +1424,30 @@ using .Main.OffsetArrays end @testset "Check push!($a, $args...)" for - a in (["foo", "Bar"], SimpleArray(["foo", "Bar"]), OffsetVector(["foo", "Bar"], 0:1)), + a in (["foo", "Bar"], SimpleArray(["foo", "Bar"]), SimpleArray{Any}(["foo", "Bar"]), OffsetVector(["foo", "Bar"], 0:1)), args in (("eenie",), ("eenie", "minie"), ("eenie", "minie", "mo")) orig = copy(a) push!(a, args...) @test length(a) == length(orig) + length(args) + @test a[axes(orig,1)] == orig @test all(a[end-length(args)+1:end] .== args) end +@testset "Check append!($a, $args)" for + a in (["foo", "Bar"], SimpleArray(["foo", "Bar"]), SimpleArray{Any}(["foo", "Bar"]), OffsetVector(["foo", "Bar"], 0:1)), + args in (("eenie",), ("eenie", "minie"), ("eenie", "minie", "mo")) + orig = copy(a) + append!(a, args) + @test length(a) == length(orig) + length(args) + @test a[axes(orig,1)] == orig + @test all(a[end-length(args)+1:end] .== args) +end + +@testset "Check sizehint!($a)" for + a in (["foo", "Bar"], SimpleArray(["foo", "Bar"]), SimpleArray{Any}(["foo", "Bar"]), OffsetVector(["foo", "Bar"], 0:1)) + @test sizehint!(a, 10) === a +end + @testset "splatting into hvcat" begin t = (1, 2) @test [t...; 3 4] == [1 2; 3 4] diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index f203d411a4424..a849ddbf982a8 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -5671,3 +5671,14 @@ end # fieldcount on `Tuple` should constant fold, even though `.fields` not const @test fully_eliminated(Base.fieldcount, Tuple{Type{Tuple{Nothing, Int, Int}}}) + +# Issue https://github.com/JuliaLang/julia/issues/55751 + +abstract type AbstractGrid55751{T, N} <: AbstractArray{T, N} end +struct Grid55751{T, N, AT} <: AbstractGrid55751{T, N} + axes::AT +end + +t155751 = Union{AbstractArray{UInt8, 4}, Array{Float32, 4}, Grid55751{Float32, 3, _A} where _A} +t255751 = Array{Float32, 3} +@test Core.Compiler.tmerge_types_slow(t155751,t255751) == AbstractArray # shouldn't hang diff --git a/test/loading.jl b/test/loading.jl index 9207294a205b5..71d0b07b64376 100644 --- a/test/loading.jl +++ b/test/loading.jl @@ -1034,6 +1034,16 @@ end end @testset "Extensions" begin + test_ext = """ + function test_ext(parent::Module, ext::Symbol) + _ext = Base.get_extension(parent, ext) + _ext isa Module || error("expected extension \$ext to be loaded") + _pkgdir = pkgdir(_ext) + _pkgdir == pkgdir(parent) != nothing || error("unexpected extension \$ext pkgdir path: \$_pkgdir") + _pkgversion = pkgversion(_ext) + _pkgversion == pkgversion(parent) || error("unexpected extension \$ext version: \$_pkgversion") + end + """ depot_path = mktempdir() try proj = joinpath(@__DIR__, "project", "Extensions", "HasDepWithExtensions.jl") @@ -1044,6 +1054,7 @@ end cmd = """ $load_distr begin + $ew $test_ext $ew push!(empty!(DEPOT_PATH), $(repr(depot_path))) using HasExtensions $ew using HasExtensions @@ -1051,6 +1062,7 @@ end $ew HasExtensions.ext_loaded && error("ext_loaded set") using HasDepWithExtensions $ew using HasDepWithExtensions + $ew test_ext(HasExtensions, :Extension) $ew Base.get_extension(HasExtensions, :Extension).extvar == 1 || error("extvar in Extension not set") $ew HasExtensions.ext_loaded || error("ext_loaded not set") $ew HasExtensions.ext_folder_loaded && error("ext_folder_loaded set") @@ -1100,11 +1112,12 @@ end test_ext_proj = """ begin + $test_ext using HasExtensions using ExtDep - Base.get_extension(HasExtensions, :Extension) isa Module || error("expected extension to load") + test_ext(HasExtensions, :Extension) using ExtDep2 - Base.get_extension(HasExtensions, :ExtensionFolder) isa Module || error("expected extension to load") + test_ext(HasExtensions, :ExtensionFolder) end """ for compile in (`--compiled-modules=no`, ``) diff --git a/test/offsetarray.jl b/test/offsetarray.jl index c50f38c382385..fb5855dfbaa0d 100644 --- a/test/offsetarray.jl +++ b/test/offsetarray.jl @@ -383,6 +383,18 @@ v2 = copy(v) @test v2[end-1] == 2 @test v2[end] == 1 +# push!(v::AbstractVector, x...) +v2 = copy(v) +@test @invoke(push!(v2::AbstractVector, 3)) === v2 +@test v2[axes(v,1)] == v +@test v2[end] == 3 +@test v2[begin] == v[begin] == v[-2] +v2 = copy(v) +@test @invoke(push!(v2::AbstractVector, 5, 6)) == v2 +@test v2[axes(v,1)] == v +@test v2[end-1] == 5 +@test v2[end] == 6 + # append! from array v2 = copy(v) @test append!(v2, [2, 1]) === v2 @@ -399,6 +411,23 @@ v2 = copy(v) @test v2[axes(v, 1)] == v @test v2[lastindex(v)+1:end] == [2, 1] +# append!(::AbstractVector, ...) +# append! from array +v2 = copy(v) +@test @invoke(append!(v2::AbstractVector, [2, 1]::Any)) === v2 +@test v2[axes(v, 1)] == v +@test v2[lastindex(v)+1:end] == [2, 1] +# append! from HasLength iterator +v2 = copy(v) +@test @invoke(append!(v2::AbstractVector, (v for v in [2, 1])::Any)) === v2 +@test v2[axes(v, 1)] == v +@test v2[lastindex(v)+1:end] == [2, 1] +# append! from SizeUnknown iterator +v2 = copy(v) +@test @invoke(append!(v2::AbstractVector, (v for v in [2, 1] if true)::Any)) === v2 +@test v2[axes(v, 1)] == v +@test v2[lastindex(v)+1:end] == [2, 1] + # other functions v = OffsetArray(v0, (-3,)) @test lastindex(v) == 1 @@ -878,3 +907,10 @@ end v = view([1,2,3,4], :) @test v[Base.IdentityUnitRange(2:3)] == OffsetArray(2:3, 2:3) end + +@testset "mapreduce with OffsetRanges" begin + r = 5:100 + a = OffsetArray(r, 2) + b = sum(a, dims=1) + @test b[begin] == sum(r) +end diff --git a/test/strings/annotated.jl b/test/strings/annotated.jl index 62bf9a0c91c00..9e24ae46fd206 100644 --- a/test/strings/annotated.jl +++ b/test/strings/annotated.jl @@ -66,6 +66,9 @@ end @testset "AnnotatedChar" begin chr = Base.AnnotatedChar('c') @test chr == Base.AnnotatedChar(chr.char, Pair{Symbol, Any}[]) + @test uppercase(chr) == Base.AnnotatedChar('C') + @test titlecase(chr) == Base.AnnotatedChar('C') + @test lowercase(Base.AnnotatedChar('C')) == chr str = Base.AnnotatedString("hmm", [(1:1, :attr => "h0h0"), (1:2, :attr => "h0m1"), (2:3, :attr => "m1m2")])