diff --git a/.github/workflows/statuses.yml b/.github/workflows/statuses.yml index 36a694a7c6d20..7116a766ad8df 100644 --- a/.github/workflows/statuses.yml +++ b/.github/workflows/statuses.yml @@ -48,8 +48,6 @@ jobs: - run: | declare -a CONTEXT_LIST=( "buildbot/tester_freebsd64" - "buildbot/tester_win32" - "buildbot/tester_win64" ) for CONTEXT in "${CONTEXT_LIST[@]}" do diff --git a/Make.inc b/Make.inc index e1420dd5bac74..dbf723f7ec4ee 100644 --- a/Make.inc +++ b/Make.inc @@ -1391,13 +1391,13 @@ define symlink_target # (from, to-dir, to-name) CLEAN_TARGETS += clean-$$(abspath $(2)/$(3)) clean-$$(abspath $(2)/$(3)): ifeq ($(BUILD_OS), WINNT) - -cmd //C rmdir $$(call mingw_to_dos,$(2)/$(3),cd $(2) &&) + -cmd //C rmdir $$(call cygpath_w,$(2)/$(3)) else -rm -r $$(abspath $(2)/$(3)) endif $$(abspath $(2)/$(3)): | $$(abspath $(2)) ifeq ($$(BUILD_OS), WINNT) - @cmd //C mklink //J $$(call mingw_to_dos,$(2)/$(3),cd $(2) &&) $$(call mingw_to_dos,$(1),) + @cmd //C mklink //J $$(call cygpath_w,$(2)/$(3)) $$(call cygpath_w,$(1)) else ifneq (,$$(findstring CYGWIN,$$(BUILD_OS))) @cmd /C mklink /J $$(call cygpath_w,$(2)/$(3)) $$(call cygpath_w,$(1)) else ifdef JULIA_VAGRANT_BUILD @@ -1415,7 +1415,7 @@ WINE ?= wine # many of the following targets must be = not := because the expansion of the makefile functions (and $1) shouldn't happen until later ifeq ($(BUILD_OS), WINNT) # MSYS spawn = $(1) -cygpath_w = $(1) +cygpath_w = `cygpath -w $(1)` else ifneq (,$(findstring CYGWIN,$(BUILD_OS))) # Cygwin spawn = $(1) cygpath_w = `cygpath -w $(1)` diff --git a/Makefile b/Makefile index d38311dce720a..57b5953107914 100644 --- a/Makefile +++ b/Makefile @@ -222,8 +222,10 @@ endif endif endif +# Note that we disable MSYS2's path munging here, as otherwise +# it replaces our `:`-separated list as a `;`-separated one. define stringreplace - $(build_depsbindir)/stringreplace $$(strings -t x - $1 | grep $2 | awk '{print $$1;}') $3 255 "$(call cygpath_w,$1)" + MSYS2_ARG_CONV_EXCL='*' $(build_depsbindir)/stringreplace $$(strings -t x - $1 | grep $2 | awk '{print $$1;}') $3 255 "$(call cygpath_w,$1)" endef @@ -446,8 +448,9 @@ endif exe: - # run Inno Setup to compile installer - $(call spawn,$(JULIAHOME)/dist-extras/inno/iscc.exe /DAppVersion=$(JULIA_VERSION) /DSourceDir="$(call cygpath_w,$(BUILDROOT)/julia-$(JULIA_COMMIT))" /DRepoDir="$(call cygpath_w,$(JULIAHOME))" /F"$(JULIA_BINARYDIST_FILENAME)" /O"$(call cygpath_w,$(BUILDROOT))" $(INNO_ARGS) $(call cygpath_w,$(JULIAHOME)/contrib/windows/build-installer.iss)) + # run Inno Setup to compile installer. + # Note that we disable MSYS2 path munging, as it interferes with the `/` options: + MSYS2_ARG_CONV_EXCL='*' $(call spawn,$(JULIAHOME)/dist-extras/inno/iscc.exe /DAppVersion=$(JULIA_VERSION) /DSourceDir="$(call cygpath_w,$(BUILDROOT)/julia-$(JULIA_COMMIT))" /DRepoDir="$(call cygpath_w,$(JULIAHOME))" /F"$(JULIA_BINARYDIST_FILENAME)" /O"$(call cygpath_w,$(BUILDROOT))" $(INNO_ARGS) $(call cygpath_w,$(JULIAHOME)/contrib/windows/build-installer.iss)) chmod a+x "$(BUILDROOT)/$(JULIA_BINARYDIST_FILENAME).exe" app: @@ -572,7 +575,7 @@ win-extras: cd $(JULIAHOME)/dist-extras && \ $(JLDOWNLOAD) https://www.jrsoftware.org/download.php/is.exe && \ chmod a+x is.exe && \ - $(call spawn, $(JULIAHOME)/dist-extras/is.exe /DIR="$(call cygpath_w,$(JULIAHOME)/dist-extras/inno)" /PORTABLE=1 /CURRENTUSER /VERYSILENT) + MSYS2_ARG_CONV_EXCL='*' $(call spawn, $(JULIAHOME)/dist-extras/is.exe /DIR="$(call cygpath_w,$(JULIAHOME)/dist-extras/inno)" /PORTABLE=1 /CURRENTUSER /VERYSILENT) # various statistics about the build that may interest the user ifeq ($(USE_SYSTEM_LLVM), 1) diff --git a/NEWS.md b/NEWS.md index 91fb4bf6d3b5f..62683964eb884 100644 --- a/NEWS.md +++ b/NEWS.md @@ -111,6 +111,7 @@ New library features * `extrema` now accepts an `init` keyword argument ([#36265], [#43604]). * `Iterators.countfrom` now accepts any type that defines `+` ([#37747]). * `@time` now separates out % time spent recompiling invalidated methods ([#45015]). +* An issue with order of operations in `fld1` is now fixed ([#28973]). Standard library changes ------------------------ diff --git a/base/Base.jl b/base/Base.jl index b2e79224edbd7..79c6d64c001ee 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -50,11 +50,11 @@ setproperty!(x::Tuple, f::Int, v, order::Symbol) = setfield!(x, f, v, order) # t getproperty(x, f::Symbol, order::Symbol) = (@inline; getfield(x, f, order)) setproperty!(x, f::Symbol, v, order::Symbol) = (@inline; setfield!(x, f, convert(fieldtype(typeof(x), f), v), order)) -swapproperty!(x, f::Symbol, v, order::Symbol=:notatomic) = +swapproperty!(x, f::Symbol, v, order::Symbol=:not_atomic) = (@inline; Core.swapfield!(x, f, convert(fieldtype(typeof(x), f), v), order)) -modifyproperty!(x, f::Symbol, op, v, order::Symbol=:notatomic) = +modifyproperty!(x, f::Symbol, op, v, order::Symbol=:not_atomic) = (@inline; Core.modifyfield!(x, f, op, v, order)) -replaceproperty!(x, f::Symbol, expected, desired, success_order::Symbol=:notatomic, fail_order::Symbol=success_order) = +replaceproperty!(x, f::Symbol, expected, desired, success_order::Symbol=:not_atomic, fail_order::Symbol=success_order) = (@inline; Core.replacefield!(x, f, expected, convert(fieldtype(typeof(x), f), desired), success_order, fail_order)) convert(::Type{Any}, Core.@nospecialize x) = x diff --git a/base/abstractarray.jl b/base/abstractarray.jl index a27a9cd7271b5..be31b406ae307 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -1249,7 +1249,7 @@ function unsafe_getindex(A::AbstractArray, I...) r end -struct CanonicalIndexError +struct CanonicalIndexError <: Exception func::String type::Any CanonicalIndexError(func::String, @nospecialize(type)) = new(func, type) @@ -3187,8 +3187,9 @@ function circshift!(a::AbstractVector, shift::Integer) n == 0 && return shift = mod(shift, n) shift == 0 && return - reverse!(a, 1, shift) - reverse!(a, shift+1, length(a)) + l = lastindex(a) + reverse!(a, firstindex(a), l-shift) + reverse!(a, l-shift+1, lastindex(a)) reverse!(a) return a end diff --git a/base/loading.jl b/base/loading.jl index 8625db41df0a2..bbb111c955ecf 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -2144,11 +2144,13 @@ end end for chi in includes f, ftime_req = chi.filename, chi.mtime - # Issue #13606: compensate for Docker images rounding mtimes - # Issue #20837: compensate for GlusterFS truncating mtimes to microseconds - # The `ftime != 1.0` condition below provides compatibility with Nix mtime. ftime = mtime(f) - if ftime != ftime_req && ftime != floor(ftime_req) && ftime != trunc(ftime_req, digits=6) && ftime != 1.0 + is_stale = ( ftime != ftime_req ) && + ( ftime != floor(ftime_req) ) && # Issue #13606, PR #13613: compensate for Docker images rounding mtimes + ( ftime != trunc(ftime_req, digits=6) ) && # Issue #20837, PR #20840: compensate for GlusterFS truncating mtimes to microseconds + ( ftime != 1.0 ) && # PR #43090: provide compatibility with Nix mtime. + !( 0 < (ftime_req - ftime) < 1e-6 ) # PR #45552: Compensate for Windows tar giving mtimes that may be incorrect by up to one microsecond + if is_stale @debug "Rejecting stale cache file $cachefile (mtime $ftime_req) because file $f (mtime $ftime) has changed" return true end diff --git a/base/logging.jl b/base/logging.jl index db7ddf37c676d..fe40c482c960f 100644 --- a/base/logging.jl +++ b/base/logging.jl @@ -668,7 +668,7 @@ function handle_message(logger::SimpleLogger, level::LogLevel, message, _module, remaining > 0 || return end buf = IOBuffer() - stream = logger.stream + stream::IO = logger.stream if !(isopen(stream)::Bool) stream = stderr end diff --git a/base/namedtuple.jl b/base/namedtuple.jl index 2157975ba30d1..7a08e4f540b51 100644 --- a/base/namedtuple.jl +++ b/base/namedtuple.jl @@ -111,7 +111,7 @@ function NamedTuple{names}(nt::NamedTuple) where {names} types = Tuple{(fieldtype(nt, idx[n]) for n in 1:length(idx))...} Expr(:new, :(NamedTuple{names, $types}), Any[ :(getfield(nt, $(idx[n]))) for n in 1:length(idx) ]...) else - length_names = length(names)::Integer + length_names = length(names::Tuple) types = Tuple{(fieldtype(typeof(nt), names[n]) for n in 1:length_names)...} NamedTuple{names, types}(map(Fix1(getfield, nt), names)) end diff --git a/base/operators.jl b/base/operators.jl index e42699062f016..e8e31ec47cf16 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -855,7 +855,7 @@ julia> x == (fld1(x, y) - 1) * y + mod1(x, y) true ``` """ -fld1(x::T, y::T) where {T<:Real} = (m = mod1(x, y); fld(x + y - m, y)) +fld1(x::T, y::T) where {T<:Real} = (m = mod1(x, y); fld((x - m) + y, y)) function fld1(x::T, y::T) where T<:Integer d = div(x, y) return d + (!signbit(x ⊻ y) & (d * y != x)) diff --git a/base/range.jl b/base/range.jl index d12a10518cd7f..404c8eaf5295a 100644 --- a/base/range.jl +++ b/base/range.jl @@ -1392,14 +1392,13 @@ function sum(r::AbstractRange{<:Real}) end function _in_range(x, r::AbstractRange) - if !isfinite(x) - return false - elseif iszero(step(r)) - return !isempty(r) && first(r) == x - else - n = round(Integer, (x - first(r)) / step(r)) + 1 - return n >= 1 && n <= length(r) && r[n] == x - end + isempty(r) && return false + f, l = first(r), last(r) + # check for NaN, Inf, and large x that may overflow in the next calculation + f <= x <= l || l <= x <= f || return false + iszero(step(r)) && return true + n = round(Integer, (x - f) / step(r)) + 1 + n >= 1 && n <= length(r) && r[n] == x end in(x::Real, r::AbstractRange{<:Real}) = _in_range(x, r) # This method needs to be defined separately since -(::T, ::T) can be implemented diff --git a/base/show.jl b/base/show.jl index 381a17f188482..658ba25173e1d 100644 --- a/base/show.jl +++ b/base/show.jl @@ -2715,6 +2715,13 @@ function dump(arg; maxdepth=DUMP_DEFAULT_MAXDEPTH) dump(IOContext(stdout, :limit => true, :module => mod), arg; maxdepth=maxdepth) end +nocolor(io::IO) = IOContext(io, :color => false) +alignment_from_show(io::IO, x::Any) = + textwidth(sprint(show, x, context=nocolor(io), sizehint=0)) + +nocolor(io::IO) = IOContext(io, :color => false) +alignment_from_show(io::IO, x::Any) = + textwidth(sprint(show, x, context=nocolor(io), sizehint=0)) """ `alignment(io, X)` returns a tuple (left,right) showing how many characters are @@ -2732,35 +2739,38 @@ julia> Base.alignment(stdout, 1 + 10im) (3, 5) ``` """ -alignment(io::IO, x::Any) = (0, length(sprint(show, x, context=io, sizehint=0))) -alignment(io::IO, x::Number) = (length(sprint(show, x, context=io, sizehint=0)), 0) -alignment(io::IO, x::Integer) = (length(sprint(show, x, context=io, sizehint=0)), 0) +alignment(io::IO, x::Any) = (0, alignment_from_show(io, x)) +alignment(io::IO, x::Number) = (alignment_from_show(io, x), 0) +alignment(io::IO, x::Integer) = (alignment_from_show(io, x), 0) function alignment(io::IO, x::Real) - m = match(r"^(.*?)((?:[\.eEfF].*)?)$", sprint(show, x, context=io, sizehint=0)) - m === nothing ? (length(sprint(show, x, context=io, sizehint=0)), 0) : - (length(m.captures[1]), length(m.captures[2])) + s = sprint(show, x, context=nocolor(io), sizehint=0) + m = match(r"^(.*?)((?:[\.eEfF].*)?)$", s) + m === nothing ? (textwidth(s), 0) : + (textwidth(m.captures[1]), textwidth(m.captures[2])) end function alignment(io::IO, x::Complex) - m = match(r"^(.*[^ef][\+\-])(.*)$", sprint(show, x, context=io, sizehint=0)) - m === nothing ? (length(sprint(show, x, context=io, sizehint=0)), 0) : - (length(m.captures[1]), length(m.captures[2])) + s = sprint(show, x, context=nocolor(io), sizehint=0) + m = match(r"^(.*[^ef][\+\-])(.*)$", s) + m === nothing ? (textwidth(s), 0) : + (textwidth(m.captures[1]), textwidth(m.captures[2])) end function alignment(io::IO, x::Rational) - m = match(r"^(.*?/)(/.*)$", sprint(show, x, context=io, sizehint=0)) - m === nothing ? (length(sprint(show, x, context=io, sizehint=0)), 0) : - (length(m.captures[1]), length(m.captures[2])) + s = sprint(show, x, context=nocolor(io), sizehint=0) + m = match(r"^(.*?/)(/.*)$", s) + m === nothing ? (textwidth(s), 0) : + (textwidth(m.captures[1]), textwidth(m.captures[2])) end function alignment(io::IO, x::Pair) - s = sprint(show, x, context=io, sizehint=0) + fullwidth = alignment_from_show(io, x) if !isdelimited(io, x) # i.e. use "=>" for display ctx = IOContext(io, :typeinfo => gettypeinfos(io, x)[1]) - left = length(sprint(show, x.first, context=ctx, sizehint=0)) + left = alignment_from_show(ctx, x.first) left += 2 * !isdelimited(ctx, x.first) # for parens around p.first left += !(get(io, :compact, false)::Bool) # spaces are added around "=>" - (left+1, length(s)-left-1) # +1 for the "=" part of "=>" + (left+1, fullwidth-left-1) # +1 for the "=" part of "=>" else - (0, length(s)) # as for x::Any + (0, fullwidth) # as for x::Any end end diff --git a/cli/Makefile b/cli/Makefile index 11855ee6244dc..16b479954c724 100644 --- a/cli/Makefile +++ b/cli/Makefile @@ -29,6 +29,14 @@ endif # Build list of dependent libraries that must be opened SHIPFLAGS += -DDEP_LIBS="\"$(LOADER_BUILD_DEP_LIBS)\"" DEBUGFLAGS += -DDEP_LIBS="\"$(LOADER_DEBUG_BUILD_DEP_LIBS)\"" +ifneq (,$(findstring MINGW,$(shell uname))) +# In MSYS2, do not perform path conversion for `DEP_LIBS`. +# https://www.msys2.org/wiki/Porting/#filesystem-namespaces +# We define this environment variable for only these two object files, +# as they're the only ones that require it at the time of writing. +$(BUILDDIR)/loader_lib.o: export MSYS2_ARG_CONV_EXCL = -DDEP_LIBS= +$(BUILDDIR)/loader_lib.dbg.obj: export MSYS2_ARG_CONV_EXCL = -DDEP_LIBS= +endif # MSYS2 EXE_OBJS := $(BUILDDIR)/loader_exe.o EXE_DOBJS := $(BUILDDIR)/loader_exe.dbg.obj diff --git a/deps/checksums/SparseArrays-1d3ec8656939cc8a2c6c67fa51b76995fd72b8a6.tar.gz/md5 b/deps/checksums/SparseArrays-1d3ec8656939cc8a2c6c67fa51b76995fd72b8a6.tar.gz/md5 new file mode 100644 index 0000000000000..1e22b80501a93 --- /dev/null +++ b/deps/checksums/SparseArrays-1d3ec8656939cc8a2c6c67fa51b76995fd72b8a6.tar.gz/md5 @@ -0,0 +1 @@ +e62b7c98591daeddeefc775c67a5a174 diff --git a/deps/checksums/SparseArrays-1d3ec8656939cc8a2c6c67fa51b76995fd72b8a6.tar.gz/sha512 b/deps/checksums/SparseArrays-1d3ec8656939cc8a2c6c67fa51b76995fd72b8a6.tar.gz/sha512 new file mode 100644 index 0000000000000..8aff3bdef2ba0 --- /dev/null +++ b/deps/checksums/SparseArrays-1d3ec8656939cc8a2c6c67fa51b76995fd72b8a6.tar.gz/sha512 @@ -0,0 +1 @@ +10552c210f4152611e65aa7a6f92e382ab3aea51abfd712ca8eb1f42826b1f0c9358bb98a0e54a8b4167f9cb9f9a84a98020be4922084480a3faeae76c072eaf diff --git a/deps/checksums/SparseArrays-aa51c9b82d952502139213715c9b077ec36c4623.tar.gz/md5 b/deps/checksums/SparseArrays-aa51c9b82d952502139213715c9b077ec36c4623.tar.gz/md5 deleted file mode 100644 index dc29e4d73a572..0000000000000 --- a/deps/checksums/SparseArrays-aa51c9b82d952502139213715c9b077ec36c4623.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -c800768d427797e16c1dfb050e3615f6 diff --git a/deps/checksums/SparseArrays-aa51c9b82d952502139213715c9b077ec36c4623.tar.gz/sha512 b/deps/checksums/SparseArrays-aa51c9b82d952502139213715c9b077ec36c4623.tar.gz/sha512 deleted file mode 100644 index 093da363d2c6a..0000000000000 --- a/deps/checksums/SparseArrays-aa51c9b82d952502139213715c9b077ec36c4623.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -fe7966ba74a473c99c591bcc18ac8827949b8a764bf4e70991567cb0eb7fc8adeb2674ee09467ef431684d4ad3dbfc81d5f3df0bea7c48ca3a212b8de446303a diff --git a/doc/src/devdocs/build/windows.md b/doc/src/devdocs/build/windows.md index fef4413db7d1a..1f5f03cb7aac8 100644 --- a/doc/src/devdocs/build/windows.md +++ b/doc/src/devdocs/build/windows.md @@ -118,11 +118,67 @@ MinGW-w64 compilers available through Cygwin's package manager. ### Compiling with MinGW/MSYS2 -Compiling Julia from source using [MSYS2](https://msys2.github.io) has worked in the past -but is not actively supported. Pull requests to restore support would be welcome. See a -[past version of this -file](https://github.com/JuliaLang/julia/blob/v0.6.0/README.windows.md) for the former -instructions for compiling using MSYS2. +> MSYS2 provides a robust MSYS experience. + +Note: MSYS2 requires **64 bit** Windows 7 or newer. + + 1. Install and configure [MSYS2](https://www.msys2.org/), Software Distribution + and Building Platform for Windows. + + 1. Download and run the latest installer for the + [64-bit](https://github.com/msys2/msys2-installer/releases/latest) distribution. + The installer will have a name like `msys2-x86_64-yyyymmdd.exe`. + + 2. Open MSYS2. Update package database and base packages: + ```sh + pacman -Syu + ``` + + 3. Exit and restart MSYS2, Update the rest of the base packages: + ```sh + pacman -Syu + ``` + + 3. Then install tools required to build julia: + ```sh + # tools + pacman -S cmake diffutils git m4 make patch tar p7zip curl python + + # For 64 bit Julia, install x86_64 + pacman -S mingw-w64-x86_64-gcc + # For 32 bit Julia, install i686 + pacman -S mingw-w64-i686-gcc + ``` + + 4. Configuration of MSYS2 is complete. Now `exit` the MSYS2 shell. + + + 2. Build Julia and its dependencies with pre-build dependencies. + + 1. Open a new [**MINGW64/MINGW32 shell**](https://www.msys2.org/docs/environments/#overview). + Currently we can't use both mingw32 and mingw64, + so if you want to build the x86_64 and i686 versions, + you'll need to build them in each environment separately. + + 2. and clone the Julia sources + ```sh + git clone https://github.com/JuliaLang/julia.git + cd julia + ``` + + 3. Start the build + ```sh + make -j$(nproc) + ``` + + > Protip: build in dir + > ```sh + > make O=julia-mingw-w64 configure + > echo 'ifeq ($(BUILDROOT),$(JULIAHOME)) + > $(error "in-tree build disabled") + > endif' >> Make.user + > make -C julia-mingw-w64 + > ``` ### Cross-compiling from Unix (Linux/Mac/WSL) diff --git a/src/Makefile b/src/Makefile index 475f2eb949d6e..8ef266c8e42d3 100644 --- a/src/Makefile +++ b/src/Makefile @@ -154,12 +154,12 @@ OSLIBS += $(SRCDIR)/mach_dyld_atfork.tbd endif COMMON_LIBPATHS := -L$(build_libdir) -L$(build_shlibdir) -RT_LIBS := $(LIBUV) $(LIBUTF8PROC) $(NO_WHOLE_ARCHIVE) $(LIBUNWIND) $(RT_LLVMLINK) $(OSLIBS) -CG_LIBS := $(NO_WHOLE_ARCHIVE) $(LIBUV) $(LIBUNWIND) $(CG_LLVMLINK) $(OSLIBS) +RT_LIBS := $(WHOLE_ARCHIVE) $(LIBUV) $(WHOLE_ARCHIVE) $(LIBUTF8PROC) $(NO_WHOLE_ARCHIVE) $(LIBUNWIND) $(RT_LLVMLINK) $(OSLIBS) +CG_LIBS := $(LIBUNWIND) $(CG_LLVMLINK) $(OSLIBS) RT_DEBUG_LIBS := $(COMMON_LIBPATHS) $(WHOLE_ARCHIVE) $(BUILDDIR)/flisp/libflisp-debug.a $(WHOLE_ARCHIVE) $(BUILDDIR)/support/libsupport-debug.a -ljulia-debug $(RT_LIBS) -CG_DEBUG_LIBS := $(COMMON_LIBPATHS) $(WHOLE_ARCHIVE) $(WHOLE_ARCHIVE) $(CG_LIBS) -ljulia-debug -ljulia-internal-debug +CG_DEBUG_LIBS := $(COMMON_LIBPATHS) $(CG_LIBS) -ljulia-debug -ljulia-internal-debug RT_RELEASE_LIBS := $(COMMON_LIBPATHS) $(WHOLE_ARCHIVE) $(BUILDDIR)/flisp/libflisp.a $(WHOLE_ARCHIVE) $(BUILDDIR)/support/libsupport.a -ljulia $(RT_LIBS) -CG_RELEASE_LIBS := $(COMMON_LIBPATHS) $(WHOLE_ARCHIVE) $(WHOLE_ARCHIVE) $(CG_LIBS) -ljulia -ljulia-internal +CG_RELEASE_LIBS := $(COMMON_LIBPATHS) $(CG_LIBS) -ljulia -ljulia-internal OBJS := $(SRCS:%=$(BUILDDIR)/%.o) DOBJS := $(SRCS:%=$(BUILDDIR)/%.dbg.obj) diff --git a/src/abi_aarch64.cpp b/src/abi_aarch64.cpp index 1a3f160329c6c..514c3c5a81a6d 100644 --- a/src/abi_aarch64.cpp +++ b/src/abi_aarch64.cpp @@ -43,9 +43,11 @@ Type *get_llvm_vectype(jl_datatype_t *dt, LLVMContext &ctx) const // the homogeneity check. jl_datatype_t *ft0 = (jl_datatype_t*)jl_field_type(dt, 0); // `ft0` should be a `VecElement` type and the true element type - // should be a primitive type - if (ft0->name != jl_vecelement_typename || - ((jl_datatype_t*)jl_field_type(ft0, 0))->layout->nfields) + // should be a primitive type (nfields == 0) + if (!jl_is_datatype(ft0) || ft0->name != jl_vecelement_typename) + return nullptr; + jl_datatype_t *ft00 = (jl_datatype_t*)jl_field_type(ft0, 0); + if (!jl_is_datatype(ft00) || ft00->layout->nfields) return nullptr; for (size_t i = 1; i < nfields; i++) { if (jl_field_type(dt, i) != (jl_value_t*)ft0) { @@ -120,15 +122,17 @@ bool isHFAorHVA(jl_datatype_t *dt, size_t dsz, size_t &nele, ElementType &ele, L // For composite types, find the first non zero sized member size_t i; size_t fieldsz; - for (i = 0;i < nfields;i++) { + for (i = 0; i < nfields; i++) { if ((fieldsz = jl_field_size(dt, i))) { break; } } assert(i < nfields); - // If there's only one non zero sized member, try again on this member + // If there's only one non-zero sized member, try again on this member if (fieldsz == dsz) { dt = (jl_datatype_t*)jl_field_type(dt, i); + if (!jl_is_datatype(dt)) + return false; continue; } if (Type *vectype = get_llvm_vectype(dt, ctx)) { @@ -140,11 +144,13 @@ bool isHFAorHVA(jl_datatype_t *dt, size_t dsz, size_t &nele, ElementType &ele, L return true; } // Otherwise, process each members - for (;i < nfields;i++) { + for (; i < nfields; i++) { size_t fieldsz = jl_field_size(dt, i); if (fieldsz == 0) continue; jl_datatype_t *fieldtype = (jl_datatype_t*)jl_field_type(dt, i); + if (!jl_is_datatype(dt)) + return false; // Check element count. // This needs to be done after the zero size member check if (nele > 3 || !isHFAorHVA(fieldtype, fieldsz, nele, ele, ctx)) { diff --git a/src/abi_arm.cpp b/src/abi_arm.cpp index 4987d07657ae6..441aa95b1fdf6 100644 --- a/src/abi_arm.cpp +++ b/src/abi_arm.cpp @@ -91,6 +91,8 @@ size_t isLegalHA(jl_datatype_t *dt, Type *&base, LLVMContext &ctx) const size_t parent_members = jl_datatype_nfields(dt); for (size_t i = 0; i < parent_members; ++i) { jl_datatype_t *fdt = (jl_datatype_t*)jl_field_type(dt,i); + if (!jl_is_datatype(fdt)) + return 0; Type *T = isLegalHAType(fdt, ctx); if (T) diff --git a/src/abi_ppc64le.cpp b/src/abi_ppc64le.cpp index 016eebd455525..2e18acdbd4f4b 100644 --- a/src/abi_ppc64le.cpp +++ b/src/abi_ppc64le.cpp @@ -44,6 +44,9 @@ struct ABI_PPC64leLayout : AbiLayout { // count the homogeneous floating aggregate size (saturating at max count of 8) unsigned isHFA(jl_datatype_t *ty, jl_datatype_t **ty0, bool *hva) const { + if (jl_datatype_size(ty) > 128 || ty->layout->npointers || ty->layout->haspadding) + return 9; + size_t i, l = ty->layout->nfields; // handle homogeneous float aggregates if (l == 0) { @@ -52,7 +55,7 @@ unsigned isHFA(jl_datatype_t *ty, jl_datatype_t **ty0, bool *hva) const *hva = false; if (*ty0 == NULL) *ty0 = ty; - else if (*hva || ty->size != (*ty0)->size) + else if (*hva || jl_datatype_size(ty) != jl_datatype_size(*ty0)) return 9; return 1; } @@ -69,7 +72,7 @@ unsigned isHFA(jl_datatype_t *ty, jl_datatype_t **ty0, bool *hva) const *hva = true; if (*ty0 == NULL) *ty0 = ty; - else if (!*hva || ty->size != (*ty0)->size) + else if (!*hva || jl_datatype_size(ty) != jl_datatype_size(*ty0)) return 9; for (i = 1; i < l; i++) { jl_datatype_t *fld = (jl_datatype_t*)jl_field_type(ty, i); diff --git a/src/abi_x86_64.cpp b/src/abi_x86_64.cpp index 43e539b8386ce..c3d12417e6de8 100644 --- a/src/abi_x86_64.cpp +++ b/src/abi_x86_64.cpp @@ -153,6 +153,10 @@ void classifyType(Classification& accum, jl_datatype_t *dt, uint64_t offset) con jl_value_t *ty = jl_field_type(dt, i); if (jl_field_isptr(dt, i)) ty = (jl_value_t*)jl_voidpointer_type; + else if (!jl_is_datatype(ty)) { // inline union + accum.addField(offset, Memory); + continue; + } classifyType(accum, (jl_datatype_t*)ty, offset + jl_field_offset(dt, i)); } } diff --git a/src/codegen.cpp b/src/codegen.cpp index c7aba9a4942cd..5076b7ee44bdb 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3955,25 +3955,6 @@ static jl_cgval_t emit_sparam(jl_codectx_t &ctx, size_t i) return mark_julia_type(ctx, sp, true, jl_any_type); } -static jl_cgval_t emit_global(jl_codectx_t &ctx, jl_sym_t *sym) -{ - jl_binding_t *jbp = NULL; - Value *bp = global_binding_pointer(ctx, ctx.module, sym, &jbp, false); - assert(bp != NULL); - if (jbp && jbp->value != NULL) { - if (jbp->constp) - return mark_julia_const(ctx, jbp->value); - // double-check that a global variable is actually defined. this - // can be a problem in parallel when a definition is missing on - // one machine. - LoadInst *v = ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, bp, Align(sizeof(void*))); - v->setOrdering(AtomicOrdering::Unordered); - tbaa_decorate(ctx.tbaa().tbaa_binding, v); - return mark_julia_type(ctx, v, true, jl_any_type); - } - return emit_checked_var(ctx, bp, sym, false, ctx.tbaa().tbaa_binding); -} - static jl_cgval_t emit_isdefined(jl_codectx_t &ctx, jl_value_t *sym) { Value *isnull = NULL; @@ -4626,7 +4607,7 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaval) { if (jl_is_symbol(expr)) { jl_sym_t *sym = (jl_sym_t*)expr; - return emit_global(ctx, sym); + return emit_globalref(ctx, ctx.module, sym, AtomicOrdering::Unordered); } if (jl_is_slot(expr) || jl_is_argument(expr)) { return emit_local(ctx, expr); diff --git a/src/dlload.c b/src/dlload.c index 33afe62acad90..8932420e2af14 100644 --- a/src/dlload.c +++ b/src/dlload.c @@ -259,6 +259,10 @@ JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags, #ifdef _OS_WINDOWS_ err = GetLastError(); break; // LoadLibrary already tested the rest +#else + // bail out and show the error if file actually exists + if (jl_stat(path, (char*)&stbuf) == 0) + break; #endif } diff --git a/src/dump.c b/src/dump.c index 8cb2f901ee45b..920a6981db095 100644 --- a/src/dump.c +++ b/src/dump.c @@ -120,11 +120,6 @@ static jl_typename_t *jl_idtable_typename = NULL; static jl_value_t *jl_bigint_type = NULL; static int gmp_limb_size = 0; -static void write_uint64(ios_t *s, uint64_t i) JL_NOTSAFEPOINT -{ - ios_write(s, (char*)&i, 8); -} - static void write_float64(ios_t *s, double x) JL_NOTSAFEPOINT { write_uint64(s, *((uint64_t*)&x)); @@ -583,13 +578,15 @@ static int jl_serialize_generic(jl_serializer_state *s, jl_value_t *v) JL_GC_DIS return 0; } -static void jl_serialize_code_instance(jl_serializer_state *s, jl_code_instance_t *codeinst, int skip_partial_opaque, int internal) JL_GC_DISABLED +static void jl_serialize_code_instance(jl_serializer_state *s, jl_code_instance_t *codeinst, + int skip_partial_opaque, int internal, + int force) JL_GC_DISABLED { if (internal > 2) { while (codeinst && !codeinst->relocatability) codeinst = codeinst->next; } - if (jl_serialize_generic(s, (jl_value_t*)codeinst)) { + if (!force && jl_serialize_generic(s, (jl_value_t*)codeinst)) { return; } @@ -609,7 +606,7 @@ static void jl_serialize_code_instance(jl_serializer_state *s, jl_code_instance_ if (write_ret_type && codeinst->rettype_const && jl_typeis(codeinst->rettype_const, jl_partial_opaque_type)) { if (skip_partial_opaque) { - jl_serialize_code_instance(s, codeinst->next, skip_partial_opaque, internal); + jl_serialize_code_instance(s, codeinst->next, skip_partial_opaque, internal, 0); return; } else { @@ -636,7 +633,7 @@ static void jl_serialize_code_instance(jl_serializer_state *s, jl_code_instance_ jl_serialize_value(s, jl_nothing); } write_uint8(s->s, codeinst->relocatability); - jl_serialize_code_instance(s, codeinst->next, skip_partial_opaque, internal); + jl_serialize_code_instance(s, codeinst->next, skip_partial_opaque, internal, 0); } enum METHOD_SERIALIZATION_MODE { @@ -893,10 +890,10 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li } jl_serialize_value(s, (jl_value_t*)backedges); jl_serialize_value(s, (jl_value_t*)NULL); //callbacks - jl_serialize_code_instance(s, mi->cache, 1, internal); + jl_serialize_code_instance(s, mi->cache, 1, internal, 0); } else if (jl_is_code_instance(v)) { - jl_serialize_code_instance(s, (jl_code_instance_t*)v, 0, 2); + jl_serialize_code_instance(s, (jl_code_instance_t*)v, 0, 2, 1); } else if (jl_typeis(v, jl_module_type)) { jl_serialize_module(s, (jl_module_t*)v); @@ -924,7 +921,7 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li } else { write_uint8(s->s, TAG_INT64); - write_int64(s->s, *(int64_t*)data); + write_uint64(s->s, *(int64_t*)data); } } else if (jl_typeis(v, jl_int32_type)) { @@ -1478,7 +1475,7 @@ static int64_t write_dependency_list(ios_t *s, jl_array_t **udepsp) ios_seek(s, initial_pos); write_uint64(s, pos - initial_pos); ios_seek(s, pos); - write_int64(s, 0); + write_uint64(s, 0); } return pos; } @@ -2713,7 +2710,7 @@ JL_DLLEXPORT int jl_save_incremental(const char *fname, jl_array_t *worklist) // Go back and update the source-text position to point to the current position int64_t posfile = ios_pos(&f); ios_seek(&f, srctextpos); - write_int64(&f, posfile); + write_uint64(&f, posfile); ios_seek_end(&f); // Each source-text file is written as // int32: length of abspath diff --git a/src/gc.c b/src/gc.c index b60cc4ff7e8d6..893b76139b7e6 100644 --- a/src/gc.c +++ b/src/gc.c @@ -2457,6 +2457,16 @@ module_binding: { void *vb = jl_astaggedvalue(b); verify_parent1("module", binding->parent, &vb, "binding_buff"); (void)vb; + jl_value_t *ty = jl_atomic_load_relaxed(&b->ty); + if (ty && ty != (jl_value_t*)jl_any_type) { + verify_parent2("module", binding->parent, + &b->ty, "binding(%s)", jl_symbol_name(b->name)); + if (gc_try_setmark(ty, &binding->nptr, &tag, &bits)) { + new_obj = ty; + gc_repush_markdata(&sp, gc_mark_binding_t); + goto mark; + } + } jl_value_t *value = jl_atomic_load_relaxed(&b->value); jl_value_t *globalref = jl_atomic_load_relaxed(&b->globalref); if (value) { diff --git a/src/ircode.c b/src/ircode.c index 46056114a1c8d..34428cff79fe8 100644 --- a/src/ircode.c +++ b/src/ircode.c @@ -80,7 +80,7 @@ static void jl_encode_as_indexed_root(jl_ircode_state *s, jl_value_t *v) assert(id >= 0); if (rr.key) { write_uint8(s->s, TAG_RELOC_METHODROOT); - write_int64(s->s, rr.key); + write_uint64(s->s, rr.key); } if (id < 256) { write_uint8(s->s, TAG_METHODROOT); @@ -283,7 +283,7 @@ static void jl_encode_value_(jl_ircode_state *s, jl_value_t *v, int as_literal) } else { write_uint8(s->s, TAG_INT64); - write_int64(s->s, *(int64_t*)data); + write_uint64(s->s, *(int64_t*)data); } } else if (jl_typeis(v, jl_int32_type)) { diff --git a/src/llvm-alloc-helpers.cpp b/src/llvm-alloc-helpers.cpp index 55a93ea5179b5..886427ed01145 100644 --- a/src/llvm-alloc-helpers.cpp +++ b/src/llvm-alloc-helpers.cpp @@ -161,7 +161,12 @@ void jl_alloc::runEscapeAnalysis(llvm::Instruction *I, EscapeAnalysisRequiredArg auto check_inst = [&] (Instruction *inst, Use *use) { if (isa(inst)) { required.use_info.hasload = true; - if (cur.offset == UINT32_MAX || !required.use_info.addMemOp(inst, 0, cur.offset, + if (cur.offset == UINT32_MAX) { + auto elty = inst->getType(); + required.use_info.has_unknown_objref |= hasObjref(elty); + required.use_info.has_unknown_objrefaggr |= hasObjref(elty) && !isa(elty); + required.use_info.hasunknownmem = true; + } else if (!required.use_info.addMemOp(inst, 0, cur.offset, inst->getType(), false, required.DL)) required.use_info.hasunknownmem = true; @@ -229,7 +234,12 @@ void jl_alloc::runEscapeAnalysis(llvm::Instruction *I, EscapeAnalysisRequiredArg return false; } auto storev = store->getValueOperand(); - if (cur.offset == UINT32_MAX || !required.use_info.addMemOp(inst, use->getOperandNo(), + if (cur.offset == UINT32_MAX) { + auto elty = storev->getType(); + required.use_info.has_unknown_objref |= hasObjref(elty); + required.use_info.has_unknown_objrefaggr |= hasObjref(elty) && !isa(elty); + required.use_info.hasunknownmem = true; + } else if (!required.use_info.addMemOp(inst, use->getOperandNo(), cur.offset, storev->getType(), true, required.DL)) required.use_info.hasunknownmem = true; diff --git a/src/llvm-alloc-helpers.h b/src/llvm-alloc-helpers.h index 3f06baddfcff6..b0c675ae59cc8 100644 --- a/src/llvm-alloc-helpers.h +++ b/src/llvm-alloc-helpers.h @@ -87,6 +87,11 @@ namespace jl_alloc { // The object is used in an error function bool haserror:1; + // The alloc has a Julia object reference not in an explicit field. + bool has_unknown_objref:1; + // The alloc has an aggregate Julia object reference not in an explicit field. + bool has_unknown_objrefaggr:1; + void reset() { escaped = false; @@ -99,6 +104,8 @@ namespace jl_alloc { hasunknownmem = false; returned = false; haserror = false; + has_unknown_objref = false; + has_unknown_objrefaggr = false; uses.clear(); preserves.clear(); memops.clear(); diff --git a/src/llvm-alloc-opt.cpp b/src/llvm-alloc-opt.cpp index 3f270cde8d96d..d9ddc7a15b9fb 100644 --- a/src/llvm-alloc-opt.cpp +++ b/src/llvm-alloc-opt.cpp @@ -233,8 +233,8 @@ void Optimizer::optimizeAll() removeAlloc(orig); continue; } - bool has_ref = false; - bool has_refaggr = false; + bool has_ref = use_info.has_unknown_objref; + bool has_refaggr = use_info.has_unknown_objrefaggr; for (auto memop: use_info.memops) { auto &field = memop.second; if (field.hasobjref) { @@ -314,7 +314,10 @@ ssize_t Optimizer::getGCAllocSize(Instruction *I) if (call->getCalledOperand() != pass.alloc_obj_func) return -1; assert(call->arg_size() == 3); - size_t sz = (size_t)cast(call->getArgOperand(1))->getZExtValue(); + auto CI = dyn_cast(call->getArgOperand(1)); + if (!CI) + return -1; + size_t sz = (size_t)CI->getZExtValue(); if (sz < IntegerType::MAX_INT_BITS / 8 && sz < INT32_MAX) return sz; return -1; @@ -574,7 +577,9 @@ void Optimizer::moveToStack(CallInst *orig_inst, size_t sz, bool has_ref) // treat this as a non-mem2reg'd alloca // The ccall root and GC preserve handling below makes sure that // the alloca isn't optimized out. - buff = prolog_builder.CreateAlloca(pass.T_prjlvalue); + const DataLayout &DL = F.getParent()->getDataLayout(); + auto asize = ConstantInt::get(Type::getInt64Ty(prolog_builder.getContext()), sz / DL.getTypeAllocSize(pass.T_prjlvalue)); + buff = prolog_builder.CreateAlloca(pass.T_prjlvalue, asize); buff->setAlignment(Align(align)); ptr = cast(prolog_builder.CreateBitCast(buff, pass.T_pint8)); } diff --git a/src/llvm-late-gc-lowering.cpp b/src/llvm-late-gc-lowering.cpp index 9f716db3898d5..ab0ffff8944ac 100644 --- a/src/llvm-late-gc-lowering.cpp +++ b/src/llvm-late-gc-lowering.cpp @@ -419,7 +419,7 @@ unsigned getCompositeNumElements(Type *T) { // Walk through a Type, and record the element path to every tracked value inside void TrackCompositeType(Type *T, std::vector &Idxs, std::vector> &Numberings) { if (isa(T)) { - if (T->getPointerAddressSpace() == AddressSpace::Tracked) + if (isSpecialPtr(T)) Numberings.push_back(Idxs); } else if (isa(T) || isa(T) || isa(T)) { diff --git a/src/serialize.h b/src/serialize.h index 817591b989f93..4ed9874b3bb30 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -92,7 +92,7 @@ static uint64_t read_uint64(ios_t *s) JL_NOTSAFEPOINT return x; } -static void write_int64(ios_t *s, int64_t i) JL_NOTSAFEPOINT +static inline void write_uint64(ios_t *s, uint64_t i) JL_NOTSAFEPOINT { ios_write(s, (char*)&i, 8); } @@ -121,6 +121,19 @@ static uint32_t read_uint32(ios_t *s) JL_NOTSAFEPOINT return x; } +#ifdef _P64 +#define write_uint(s, i) write_uint64(s, i) +#else +#define write_uint(s, i) write_uint32(s, i) +#endif + +#ifdef _P64 +#define read_uint(s) read_uint64(s) +#else +#define read_uint(s) read_uint32(s) +#endif + + void *jl_lookup_ser_tag(jl_value_t *v); void *jl_lookup_common_symbol(jl_value_t *v); jl_value_t *jl_deser_tag(uint8_t tag); diff --git a/src/staticdata.c b/src/staticdata.c index 1b98601026d49..d1a7bcda8b75c 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -357,9 +357,28 @@ typedef enum { } jl_callingconv_t; +#ifdef _P64 +#define RELOC_TAG_OFFSET 61 +#else // this supports up to 8 RefTags, 512MB of pointer data, and 4/2 (64/32-bit) GB of constant data. -// if a larger size is required, will need to add support for writing larger relocations in many cases below #define RELOC_TAG_OFFSET 29 +#endif + +#if RELOC_TAG_OFFSET <= 32 +typedef uint32_t reloc_t; +#else +typedef uint64_t reloc_t; +#endif +static void write_reloc_t(ios_t *s, uintptr_t reloc_id) JL_NOTSAFEPOINT +{ + if (sizeof(reloc_t) <= sizeof(uint32_t)) { + assert(reloc_id < UINT32_MAX); + write_uint32(s, reloc_id); + } + else { + write_uint64(s, reloc_id); + } +} /* read and write in host byte order */ @@ -639,10 +658,9 @@ static void record_gvar(jl_serializer_state *s, int gid, uintptr_t reloc_id) JL_ { if (gid == 0) return; - ios_ensureroom(s->gvar_record, gid * sizeof(uint32_t)); - ios_seek(s->gvar_record, (gid - 1) * sizeof(uint32_t)); - assert(reloc_id < UINT32_MAX); - write_uint32(s->gvar_record, reloc_id); + ios_ensureroom(s->gvar_record, gid * sizeof(reloc_t)); + ios_seek(s->gvar_record, (gid - 1) * sizeof(reloc_t)); + write_reloc_t(s->gvar_record, reloc_id); } @@ -661,7 +679,7 @@ static void write_padding(ios_t *s, size_t nb) JL_NOTSAFEPOINT static void write_pointer(ios_t *s) JL_NOTSAFEPOINT { assert((ios_pos(s) & (sizeof(void*) - 1)) == 0 && "stream misaligned for writing a word-sized value"); - write_padding(s, sizeof(void*)); + write_uint(s, 0); } // Return the integer `id` for `v`. Generically this is looked up in `backref_table`, @@ -1116,18 +1134,20 @@ static void jl_write_values(jl_serializer_state *s) assert(invokeptr_id > 0); ios_ensureroom(s->fptr_record, invokeptr_id * sizeof(void*)); ios_seek(s->fptr_record, (invokeptr_id - 1) * sizeof(void*)); - write_uint32(s->fptr_record, ~reloc_offset); + write_reloc_t(s->fptr_record, (reloc_t)~reloc_offset); #ifdef _P64 - write_padding(s->fptr_record, 4); + if (sizeof(reloc_t) < 8) + write_padding(s->fptr_record, 8 - sizeof(reloc_t)); #endif } if (specfptr_id) { assert(specfptr_id > invokeptr_id && specfptr_id > 0); ios_ensureroom(s->fptr_record, specfptr_id * sizeof(void*)); ios_seek(s->fptr_record, (specfptr_id - 1) * sizeof(void*)); - write_uint32(s->fptr_record, reloc_offset); + write_reloc_t(s->fptr_record, reloc_offset); #ifdef _P64 - write_padding(s->fptr_record, 4); + if (sizeof(reloc_t) < 8) + write_padding(s->fptr_record, 8 - sizeof(reloc_t)); #endif } } @@ -1250,14 +1270,6 @@ static void jl_write_gv_tagrefs(jl_serializer_state *s) } } -static inline uint32_t load_uint32(uintptr_t *base) -{ - uint32_t v = jl_load_unaligned_i32((void*)*base); - *base += 4; - return v; -} - - // In deserialization, create Symbols and set up the // index for backreferencing static void jl_read_symbols(jl_serializer_state *s) @@ -1266,7 +1278,8 @@ static void jl_read_symbols(jl_serializer_state *s) uintptr_t base = (uintptr_t)&s->symbols->buf[0]; uintptr_t end = base + s->symbols->size; while (base < end) { - uint32_t len = load_uint32(&base); + uint32_t len = jl_load_unaligned_i32((void*)base); + base += 4; const char *str = (const char*)base; base += len + 1; //printf("symbol %3d: %s\n", len, str); @@ -1324,7 +1337,7 @@ static uintptr_t get_reloc_for_item(uintptr_t reloc_item, size_t reloc_offset) } // Compute target location at deserialization -static inline uintptr_t get_item_for_reloc(jl_serializer_state *s, uintptr_t base, size_t size, uint32_t reloc_id) +static inline uintptr_t get_item_for_reloc(jl_serializer_state *s, uintptr_t base, size_t size, uintptr_t reloc_id) { enum RefTags tag = (enum RefTags)(reloc_id >> RELOC_TAG_OFFSET); size_t offset = (reloc_id & (((uintptr_t)1 << RELOC_TAG_OFFSET) - 1)); @@ -1385,62 +1398,102 @@ static inline uintptr_t get_item_for_reloc(jl_serializer_state *s, uintptr_t bas } -static void jl_write_skiplist(ios_t *s, char *base, size_t size, arraylist_t *list) +static void jl_write_reloclist(ios_t *s, char *base, size_t size, arraylist_t *list) { - size_t i; - for (i = 0; i < list->len; i += 2) { + for (size_t i = 0; i < list->len; i += 2) { + size_t last_pos = i ? (size_t)list->items[i - 2] : 0; size_t pos = (size_t)list->items[i]; size_t item = (size_t)list->items[i + 1]; uintptr_t *pv = (uintptr_t*)(base + pos); assert(pos < size && pos != 0); *pv = get_reloc_for_item(item, *pv); - // record pos in relocations list - // TODO: save space by using delta-compression - assert(pos < UINT32_MAX); - write_uint32(s, pos); + + // write pos as compressed difference. + size_t pos_diff = pos - last_pos; + while (pos_diff) { + assert(pos_diff >= 0); + if (pos_diff <= 127) { + write_int8(s, pos_diff); + break; + } + else { + // Extract the next 7 bits + int8_t ns = pos_diff & (int8_t)0x7F; + pos_diff >>= 7; + // Set the high bit if there's still more + ns |= (!!pos_diff) << 7; + write_int8(s, ns); + } + } } - write_uint32(s, 0); + write_int8(s, 0); } static void jl_write_relocations(jl_serializer_state *s) { char *base = &s->s->buf[0]; - jl_write_skiplist(s->relocs, base, s->s->size, &s->gctags_list); - jl_write_skiplist(s->relocs, base, s->s->size, &s->relocs_list); + jl_write_reloclist(s->relocs, base, s->s->size, &s->gctags_list); + jl_write_reloclist(s->relocs, base, s->s->size, &s->relocs_list); } - -static void jl_read_relocations(jl_serializer_state *s, uint8_t bits) +static void jl_read_reloclist(jl_serializer_state *s, uint8_t bits) { - uintptr_t base = (uintptr_t)&s->s->buf[0]; + uintptr_t base = (uintptr_t)s->s->buf; size_t size = s->s->size; + uintptr_t last_pos = 0; + uint8_t *current = (uint8_t *)(s->relocs->buf + s->relocs->bpos); while (1) { - uintptr_t val = (uintptr_t)&s->relocs->buf[s->relocs->bpos]; - uint32_t offset = load_uint32(&val); - s->relocs->bpos += sizeof(uint32_t); - if (offset == 0) + // Read the offset of the next object + size_t pos_diff = 0; + size_t cnt = 0; + while (1) { + assert(s->relocs->bpos <= s->relocs->size); + assert((char *)current <= (char *)(s->relocs->buf + s->relocs->size)); + int8_t c = *current++; + s->relocs->bpos += 1; + + pos_diff |= ((size_t)c & 0x7F) << (7 * cnt++); + if ((c >> 7) == 0) + break; + } + if (pos_diff == 0) break; - uintptr_t *pv = (uintptr_t*)(base + offset); + + uintptr_t pos = last_pos + pos_diff; + last_pos = pos; + uintptr_t *pv = (uintptr_t *)(base + pos); uintptr_t v = *pv; v = get_item_for_reloc(s, base, size, v); *pv = v | bits; } } -static char* sysimg_base; -static char* sysimg_relocs; +static char *sysimg_base; +static char *sysimg_relocs; void gc_sweep_sysimg(void) { - uintptr_t base = (uintptr_t)sysimg_base; - uintptr_t relocs = (uintptr_t)sysimg_relocs; - if (relocs == 0) + if (!sysimg_relocs) return; + uintptr_t base = (uintptr_t)sysimg_base; + uintptr_t last_pos = 0; + uint8_t *current = (uint8_t *)sysimg_relocs; while (1) { - uint32_t offset = load_uint32(&relocs); - if (offset == 0) + // Read the offset of the next object + size_t pos_diff = 0; + size_t cnt = 0; + while (1) { + int8_t c = *current++; + pos_diff |= ((size_t)c & 0x7F) << (7 * cnt++); + if ((c >> 7) == 0) + break; + } + if (pos_diff == 0) break; - jl_taggedvalue_t *o = (jl_taggedvalue_t*)(base + offset); + + uintptr_t pos = last_pos + pos_diff; + last_pos = pos; + jl_taggedvalue_t *o = (jl_taggedvalue_t *)(base + pos); o->bits.gc = GC_OLD; } } @@ -1449,13 +1502,12 @@ void gc_sweep_sysimg(void) static void _jl_write_value(jl_serializer_state *s, jl_value_t *v) { if (v == NULL) { - write_uint32(s->s, 0); + write_reloc_t(s->s, 0); return; } uintptr_t item = backref_id(s, v); uintptr_t reloc = get_reloc_for_item(item, 0); - assert(reloc < UINT32_MAX); - write_uint32(s->s, reloc); + write_reloc_t(s->s, reloc); } @@ -1463,9 +1515,8 @@ static jl_value_t *jl_read_value(jl_serializer_state *s) { uintptr_t base = (uintptr_t)&s->s->buf[0]; size_t size = s->s->size; - uintptr_t val = base + s->s->bpos; - uint32_t offset = load_uint32(&val); - s->s->bpos += sizeof(uint32_t); + uintptr_t offset = *(reloc_t*)(base + (uintptr_t)s->s->bpos); + s->s->bpos += sizeof(reloc_t); if (offset == 0) return NULL; return (jl_value_t*)get_item_for_reloc(s, base, size, offset); @@ -1488,12 +1539,11 @@ static void jl_update_all_fptrs(jl_serializer_state *s) jl_method_instance_t **linfos = (jl_method_instance_t**)&s->fptr_record->buf[0]; uint32_t clone_idx = 0; for (i = 0; i < sysimg_fvars_max; i++) { - uintptr_t val = (uintptr_t)&linfos[i]; - uint32_t offset = load_uint32(&val); + reloc_t offset = *(reloc_t*)&linfos[i]; linfos[i] = NULL; if (offset != 0) { int specfunc = 1; - if (offset & ((uintptr_t)1 << (8 * sizeof(uint32_t) - 1))) { + if (offset & ((uintptr_t)1 << (8 * sizeof(reloc_t) - 1))) { // if high bit is set, this is the func wrapper, not the specfunc specfunc = 0; offset = ~offset; @@ -1535,15 +1585,16 @@ static void jl_update_all_gvars(jl_serializer_state *s) size_t gvname_index = 0; uintptr_t base = (uintptr_t)&s->s->buf[0]; size_t size = s->s->size; - uintptr_t gvars = (uintptr_t)&s->gvar_record->buf[0]; - uintptr_t end = gvars + s->gvar_record->size; + reloc_t *gvars = (reloc_t*)&s->gvar_record->buf[0]; + reloc_t *end = gvars + s->gvar_record->size / sizeof(reloc_t); while (gvars < end) { - uint32_t offset = load_uint32(&gvars); + uintptr_t offset = *gvars; if (offset) { uintptr_t v = get_item_for_reloc(s, base, size, offset); *sysimg_gvars(sysimg_gvars_base, gvname_index) = v; } gvname_index += 1; + gvars++; } } @@ -1559,14 +1610,14 @@ static void jl_finalize_serializer(jl_serializer_state *s, arraylist_t *list) size_t item = (size_t)list->items[i]; size_t reloc_offset = (size_t)layout_table.items[item]; assert(reloc_offset != 0); - write_uint32(s->s, (uint32_t)reloc_offset); - write_uint32(s->s, (uint32_t)((uintptr_t)list->items[i + 1])); + write_reloc_t(s->s, reloc_offset); + write_uint8(s->s, (uintptr_t)list->items[i + 1]); } - write_uint32(s->s, 0); + write_reloc_t(s->s, 0); } -static void jl_reinit_item(jl_value_t *v, int how) JL_GC_DISABLED +static void jl_reinit_item(jl_value_t *v, uint8_t how) JL_GC_DISABLED { switch (how) { case 1: { // rehash IdDict @@ -1618,11 +1669,17 @@ static void jl_finalize_deserializer(jl_serializer_state *s) JL_GC_DISABLED // run reinitialization functions uintptr_t base = (uintptr_t)&s->s->buf[0]; while (1) { - size_t offset = read_uint32(s->s); + size_t offset; + if (sizeof(reloc_t) <= 4) { + offset = read_uint32(s->s); + } + else { + offset = read_uint64(s->s); + } if (offset == 0) break; jl_value_t *v = (jl_value_t*)(base + offset); - jl_reinit_item(v, read_uint32(s->s)); + jl_reinit_item(v, read_uint8(s->s)); } } @@ -1950,7 +2007,7 @@ static void jl_save_system_image_to_stream(ios_t *f) JL_GC_DISABLED } { // step 2: build all the sysimg sections - write_padding(&sysimg, sizeof(uint32_t)); + write_padding(&sysimg, sizeof(uintptr_t)); jl_write_values(&s); jl_write_relocations(&s); jl_write_gv_syms(&s, jl_get_root_symbol()); @@ -1966,7 +2023,7 @@ static void jl_save_system_image_to_stream(ios_t *f) JL_GC_DISABLED ); jl_exit(1); } - if (const_data.size > ((uintptr_t)1 << RELOC_TAG_OFFSET)*sizeof(void*)) { + if (const_data.size / sizeof(void*) > ((uintptr_t)1 << RELOC_TAG_OFFSET)) { jl_printf( JL_STDERR, "ERROR: system image too large: const_data.size is %jd but the limit is %" PRIxPTR "\n", @@ -1977,40 +2034,45 @@ static void jl_save_system_image_to_stream(ios_t *f) JL_GC_DISABLED } // step 3: combine all of the sections into one file - write_uint32(f, sysimg.size - sizeof(uint32_t)); - ios_seek(&sysimg, sizeof(uint32_t)); + write_uint(f, sysimg.size - sizeof(uintptr_t)); + ios_seek(&sysimg, sizeof(uintptr_t)); ios_copyall(f, &sysimg); ios_close(&sysimg); - write_uint32(f, const_data.size); + write_uint(f, const_data.size); // realign stream to max-alignment for data - write_padding(f, LLT_ALIGN(ios_pos(f), 16) - ios_pos(f)); + write_padding(f, LLT_ALIGN(ios_pos(f), JL_CACHE_BYTE_ALIGNMENT) - ios_pos(f)); ios_seek(&const_data, 0); ios_copyall(f, &const_data); ios_close(&const_data); - write_uint32(f, symbols.size); + write_uint(f, symbols.size); + write_padding(f, LLT_ALIGN(ios_pos(f), 8) - ios_pos(f)); ios_seek(&symbols, 0); ios_copyall(f, &symbols); ios_close(&symbols); - write_uint32(f, relocs.size); + write_uint(f, relocs.size); + write_padding(f, LLT_ALIGN(ios_pos(f), 8) - ios_pos(f)); ios_seek(&relocs, 0); ios_copyall(f, &relocs); ios_close(&relocs); - write_uint32(f, gvar_record.size); + write_uint(f, gvar_record.size); + write_padding(f, LLT_ALIGN(ios_pos(f), 8) - ios_pos(f)); ios_seek(&gvar_record, 0); ios_copyall(f, &gvar_record); ios_close(&gvar_record); - write_uint32(f, fptr_record.size); + write_uint(f, fptr_record.size); + write_padding(f, LLT_ALIGN(ios_pos(f), 8) - ios_pos(f)); ios_seek(&fptr_record, 0); ios_copyall(f, &fptr_record); ios_close(&fptr_record); { // step 4: record locations of special roots s.s = f; + write_padding(f, LLT_ALIGN(ios_pos(f), 8) - ios_pos(f)); size_t i; for (i = 0; tags[i] != NULL; i++) { jl_value_t *tag = *tags[i]; @@ -2019,8 +2081,8 @@ static void jl_save_system_image_to_stream(ios_t *f) JL_GC_DISABLED jl_write_value(&s, jl_global_roots_table); jl_write_value(&s, s.ptls->root_task->tls); write_uint32(f, jl_get_gs_ctr()); - write_uint32(f, jl_atomic_load_acquire(&jl_world_counter)); - write_uint32(f, jl_typeinf_world); + write_uint(f, jl_atomic_load_acquire(&jl_world_counter)); + write_uint(f, jl_typeinf_world); jl_finalize_serializer(&s, &reinit_list); jl_finalize_serializer(&s, &ccallable_list); } @@ -2107,37 +2169,43 @@ static void jl_restore_system_image_from_stream(ios_t *f) JL_GC_DISABLED // step 1: read section map assert(ios_pos(f) == 0 && f->bm == bm_mem); - size_t sizeof_sysimg = read_uint32(f); - ios_static_buffer(&sysimg, f->buf, sizeof_sysimg + sizeof(uint32_t)); + size_t sizeof_sysimg = read_uint(f); + ios_static_buffer(&sysimg, f->buf, sizeof_sysimg + sizeof(uintptr_t)); ios_skip(f, sizeof_sysimg); - size_t sizeof_constdata = read_uint32(f); + size_t sizeof_constdata = read_uint(f); // realign stream to max-alignment for data - ios_seek(f, LLT_ALIGN(ios_pos(f), 16)); + ios_seek(f, LLT_ALIGN(ios_pos(f), JL_CACHE_BYTE_ALIGNMENT)); ios_static_buffer(&const_data, f->buf + f->bpos, sizeof_constdata); ios_skip(f, sizeof_constdata); - size_t sizeof_symbols = read_uint32(f); + size_t sizeof_symbols = read_uint(f); + ios_seek(f, LLT_ALIGN(ios_pos(f), 8)); ios_static_buffer(&symbols, f->buf + f->bpos, sizeof_symbols); ios_skip(f, sizeof_symbols); - size_t sizeof_relocations = read_uint32(f); + size_t sizeof_relocations = read_uint(f); + ios_seek(f, LLT_ALIGN(ios_pos(f), 8)); assert(!ios_eof(f)); ios_static_buffer(&relocs, f->buf + f->bpos, sizeof_relocations); ios_skip(f, sizeof_relocations); - size_t sizeof_gvar_record = read_uint32(f); + size_t sizeof_gvar_record = read_uint(f); + ios_seek(f, LLT_ALIGN(ios_pos(f), 8)); assert(!ios_eof(f)); ios_static_buffer(&gvar_record, f->buf + f->bpos, sizeof_gvar_record); ios_skip(f, sizeof_gvar_record); - size_t sizeof_fptr_record = read_uint32(f); + size_t sizeof_fptr_record = read_uint(f); + ios_seek(f, LLT_ALIGN(ios_pos(f), 8)); assert(!ios_eof(f)); ios_static_buffer(&fptr_record, f->buf + f->bpos, sizeof_fptr_record); ios_skip(f, sizeof_fptr_record); // step 2: get references to special values s.s = f; + ios_seek(f, LLT_ALIGN(ios_pos(f), 8)); + assert(!ios_eof(f)); size_t i; for (i = 0; tags[i] != NULL; i++) { jl_value_t **tag = tags[i]; @@ -2153,8 +2221,8 @@ static void jl_restore_system_image_from_stream(ios_t *f) JL_GC_DISABLED jl_init_box_caches(); uint32_t gs_ctr = read_uint32(f); - jl_atomic_store_release(&jl_world_counter, read_uint32(f)); - jl_typeinf_world = read_uint32(f); + jl_atomic_store_release(&jl_world_counter, read_uint(f)); + jl_typeinf_world = read_uint(f); jl_set_gs_ctr(gs_ctr); s.s = NULL; @@ -2168,10 +2236,10 @@ static void jl_restore_system_image_from_stream(ios_t *f) JL_GC_DISABLED jl_gc_set_permalloc_region((void*)sysimg_base, (void*)(sysimg_base + sysimg.size)); s.s = &sysimg; - jl_read_relocations(&s, GC_OLD_MARKED); // gctags + jl_read_reloclist(&s, GC_OLD_MARKED); // gctags size_t sizeof_tags = ios_pos(&relocs); (void)sizeof_tags; - jl_read_relocations(&s, 0); // general relocs + jl_read_reloclist(&s, 0); // general relocs ios_close(&relocs); ios_close(&const_data); jl_update_all_gvars(&s); // gvars relocs diff --git a/src/subtype.c b/src/subtype.c index 1213cd53af2f6..5ef77f0010b4e 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -1000,7 +1000,7 @@ static int subtype_tuple_tail(jl_datatype_t *xd, jl_datatype_t *yd, int8_t R, jl { size_t lx = jl_nparams(xd); size_t ly = jl_nparams(yd); - size_t i = 0, j = 0, vx = 0, vy = 0, x_reps = 1; + size_t i = 0, j = 0, vx = 0, vy = 0, x_reps = 0; jl_value_t *lastx = NULL, *lasty = NULL; jl_value_t *xi = NULL, *yi = NULL; @@ -2840,7 +2840,7 @@ static jl_value_t *intersect_sub_datatype(jl_datatype_t *xd, jl_datatype_t *yd, JL_GC_PUSHARGS(env, envsz); jl_stenv_t tempe; init_stenv(&tempe, env, envsz); - tempe.ignore_free = 1; + tempe.intersection = tempe.ignore_free = 1; if (subtype_in_env(isuper, super_pattern, &tempe)) { jl_value_t *wr = wrapper; int i; diff --git a/stdlib/InteractiveUtils/src/clipboard.jl b/stdlib/InteractiveUtils/src/clipboard.jl index 7bc718b91b2bd..27b82343973e4 100644 --- a/stdlib/InteractiveUtils/src/clipboard.jl +++ b/stdlib/InteractiveUtils/src/clipboard.jl @@ -103,7 +103,7 @@ elseif Sys.iswindows() ccall(:memcpy, Ptr{UInt16}, (Ptr{UInt16}, Ptr{UInt16}, Csize_t), plock, x_u16, sizeof(x_u16)) unlock = ccall((:GlobalUnlock, "kernel32"), stdcall, Cint, (Ptr{UInt16},), pdata) (unlock == 0 && Libc.GetLastError() == 0) || return cleanup(:GlobalUnlock) # this should never fail - pset = ccall((:SetClipboardData, "user32"), stdcall, Ptr{UInt16}, (Cuint, Ptr{UInt16}), 13, pdata) + pset = ccall((:SetClipboardData, "user32"), stdcall, Ptr{UInt16}, (Cuint, Ptr{UInt16}), 13, pdata) # CF_UNICODETEXT pdata != pset && return cleanup(:SetClipboardData) cleanup(:success) end @@ -114,14 +114,14 @@ elseif Sys.iswindows() if cause !== :OpenClipboard ccall((:CloseClipboard, "user32"), stdcall, Cint, ()) == 0 && Base.windowserror(:CloseClipboard) # this should never fail end - if cause !== :success && (cause !== :GetClipboardData || errno != 0) + if cause !== :success && !(cause === :GetClipboardData && (errno == 0x8004006A || errno == 0x800401D3)) # ignore DV_E_CLIPFORMAT and CLIPBRD_E_BAD_DATA from GetClipboardData Base.windowserror(cause, errno) end "" end ccall((:OpenClipboard, "user32"), stdcall, Cint, (Ptr{Cvoid},), C_NULL) == 0 && return Base.windowserror(:OpenClipboard) ccall(:SetLastError, stdcall, Cvoid, (UInt32,), 0) # allow distinguishing if the clipboard simply didn't have text - pdata = ccall((:GetClipboardData, "user32"), stdcall, Ptr{UInt16}, (Cuint,), 13) + pdata = ccall((:GetClipboardData, "user32"), stdcall, Ptr{UInt16}, (Cuint,), 13) # CF_UNICODETEXT pdata == C_NULL && return cleanup(:GetClipboardData) plock = ccall((:GlobalLock, "kernel32"), stdcall, Ptr{UInt16}, (Ptr{UInt16},), pdata) plock == C_NULL && return cleanup(:GlobalLock) diff --git a/stdlib/InteractiveUtils/src/macros.jl b/stdlib/InteractiveUtils/src/macros.jl index d9dcff57257c9..5d1e6dff77478 100644 --- a/stdlib/InteractiveUtils/src/macros.jl +++ b/stdlib/InteractiveUtils/src/macros.jl @@ -24,7 +24,7 @@ function recursive_dotcalls!(ex, args, i=1) end end (start, branches) = ex.head === :. ? (1, ex.args[2].args) : (2, ex.args) - length_branches = length(branches)::Integer + length_branches = length(branches)::Int for j in start:length_branches branch, i = recursive_dotcalls!(branches[j], args, i) branches[j] = branch @@ -40,7 +40,7 @@ function gen_call_with_extracted_types(__module__, fcn, ex0, kws=Expr[]) end i = findlast(a->(Meta.isexpr(a, :kw) || Meta.isexpr(a, :parameters)), ex0.args[1].args) args = copy(ex0.args[1].args) - insert!(args, (isnothing(i) ? 2 : i+1), ex0.args[2]) + insert!(args, (isnothing(i) ? 2 : 1+i::Int), ex0.args[2]) ex0 = Expr(:call, args...) end if ex0.head === :. || (ex0.head === :call && ex0.args[1] !== :.. && string(ex0.args[1])[1] == '.') diff --git a/stdlib/LinearAlgebra/src/diagonal.jl b/stdlib/LinearAlgebra/src/diagonal.jl index 4af42d8f53eb4..a2756bb3a1201 100644 --- a/stdlib/LinearAlgebra/src/diagonal.jl +++ b/stdlib/LinearAlgebra/src/diagonal.jl @@ -770,6 +770,9 @@ end dot(A::AbstractMatrix, B::Diagonal) = conj(dot(B, A)) function _mapreduce_prod(f, x, D::Diagonal, y) + if !(length(x) == length(D.diag) == length(y)) + throw(DimensionMismatch("x has length $(length(x)), D has size $(size(D)), and y has $(length(y))")) + end if isempty(x) && isempty(D) && isempty(y) return zero(promote_op(f, eltype(x), eltype(D), eltype(y))) else diff --git a/stdlib/LinearAlgebra/test/diagonal.jl b/stdlib/LinearAlgebra/test/diagonal.jl index 2801332e840e6..007420f1eb999 100644 --- a/stdlib/LinearAlgebra/test/diagonal.jl +++ b/stdlib/LinearAlgebra/test/diagonal.jl @@ -922,10 +922,14 @@ end @test s1 == prod(sign, d) end -@testset "Empty (#35424)" begin +@testset "Empty (#35424) & size checks (#47060)" begin @test zeros(0)'*Diagonal(zeros(0))*zeros(0) === 0.0 @test transpose(zeros(0))*Diagonal(zeros(Complex{Int}, 0))*zeros(0) === 0.0 + 0.0im @test dot(zeros(Int32, 0), Diagonal(zeros(Int, 0)), zeros(Int16, 0)) === 0 + @test_throws DimensionMismatch zeros(2)' * Diagonal(zeros(2)) * zeros(3) + @test_throws DimensionMismatch zeros(3)' * Diagonal(zeros(2)) * zeros(2) + @test_throws DimensionMismatch dot(zeros(2), Diagonal(zeros(2)), zeros(3)) + @test_throws DimensionMismatch dot(zeros(3), Diagonal(zeros(2)), zeros(2)) end @testset "Diagonal(undef)" begin diff --git a/stdlib/Logging/src/ConsoleLogger.jl b/stdlib/Logging/src/ConsoleLogger.jl index 3d283e7a33456..66e1c935b41fd 100644 --- a/stdlib/Logging/src/ConsoleLogger.jl +++ b/stdlib/Logging/src/ConsoleLogger.jl @@ -117,7 +117,7 @@ function handle_message(logger::ConsoleLogger, level::LogLevel, message, _module # Generate a text representation of the message and all key value pairs, # split into lines. msglines = [(indent=0, msg=l) for l in split(chomp(convert(String, string(message))::String), '\n')] - stream = logger.stream + stream::IO = logger.stream if !(isopen(stream)::Bool) stream = stderr end diff --git a/stdlib/REPL/src/LineEdit.jl b/stdlib/REPL/src/LineEdit.jl index 3854a81ee0bcb..9215c9f574879 100644 --- a/stdlib/REPL/src/LineEdit.jl +++ b/stdlib/REPL/src/LineEdit.jl @@ -1086,7 +1086,7 @@ end function edit_transpose_chars(buf::IOBuffer) # Moving left but not transpoing anything is intentional, and matches Emacs's behavior - eof(buf) && char_move_left(buf) + eof(buf) && position(buf) !== 0 && char_move_left(buf) position(buf) == 0 && return false char_move_left(buf) pos = position(buf) diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index 07b904c6abb84..ca00da2525c5a 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -195,7 +195,7 @@ function complete_symbol(sym::String, @nospecialize(ffunc), context_module::Modu t = typeof(t.parameters[1]) end # Only look for fields if this is a concrete type - if isconcretetype(t) + if isconcretetype(t) && !(t <: Tuple) fields = fieldnames(t) for field in fields s = string(field) @@ -312,7 +312,12 @@ function complete_path(path::AbstractString, pos::Int; use_envpath=false, shell_ end function complete_expanduser(path::AbstractString, r) - expanded = expanduser(path) + expanded = + try expanduser(path) + catch e + e isa ArgumentError || rethrow() + path + end return Completion[PathCompletion(expanded)], r, path != expanded end diff --git a/stdlib/REPL/test/lineedit.jl b/stdlib/REPL/test/lineedit.jl index 87028e239d5b8..9b0569bb08424 100644 --- a/stdlib/REPL/test/lineedit.jl +++ b/stdlib/REPL/test/lineedit.jl @@ -376,6 +376,8 @@ let buf = IOBuffer() LineEdit.edit_transpose_chars(buf) @test content(buf) == "βγαδε" + + # Transposing a one-char buffer should behave like Emacs seek(buf, 0) @inferred(LineEdit.edit_clear(buf)) edit_insert(buf, "a") @@ -385,6 +387,13 @@ let buf = IOBuffer() LineEdit.edit_transpose_chars(buf) @test content(buf) == "a" @test position(buf) == 0 + + # Transposing an empty buffer shouldn't implode + seek(buf, 0) + LineEdit.edit_clear(buf) + LineEdit.edit_transpose_chars(buf) + @test content(buf) == "" + @test position(buf) == 0 end @testset "edit_word_transpose" begin diff --git a/stdlib/REPL/test/replcompletions.jl b/stdlib/REPL/test/replcompletions.jl index 1d59b6e057882..fa9f40f626f67 100644 --- a/stdlib/REPL/test/replcompletions.jl +++ b/stdlib/REPL/test/replcompletions.jl @@ -270,6 +270,12 @@ let @test isempty(c) end +# issue 46800: (3,2). errors in the REPL +let + c, r = test_complete("(3,2).") + @test isempty(c) +end + # inexistent completion inside a string let s = "Base.print(\"lol" c, r, res = test_complete(s) @@ -947,6 +953,9 @@ let s, c, r s = "\"~" @test "tmpfoobar/" in c c,r = test_complete(s) + s = "\"~user" + c, r = test_complete(s) + @test isempty(c) rm(dir) end end diff --git a/stdlib/Sockets/src/Sockets.jl b/stdlib/Sockets/src/Sockets.jl index 84fe351de99e1..9dc630c2db9fd 100644 --- a/stdlib/Sockets/src/Sockets.jl +++ b/stdlib/Sockets/src/Sockets.jl @@ -727,7 +727,7 @@ function listenany(host::IPAddr, default_port) return (addr.port, sock) end close(sock) - addr = InetAddr(addr.host, addr.port + 1) + addr = InetAddr(addr.host, addr.port + UInt16(1)) if addr.port == default_port error("no ports available") end diff --git a/stdlib/SparseArrays.version b/stdlib/SparseArrays.version index 1d93c36f6d7f0..cdee6b6ffc516 100644 --- a/stdlib/SparseArrays.version +++ b/stdlib/SparseArrays.version @@ -1,4 +1,4 @@ SPARSEARRAYS_BRANCH = main -SPARSEARRAYS_SHA1 = aa51c9b82d952502139213715c9b077ec36c4623 +SPARSEARRAYS_SHA1 = 1d3ec8656939cc8a2c6c67fa51b76995fd72b8a6 SPARSEARRAYS_GIT_URL := https://github.com/JuliaSparse/SparseArrays.jl.git SPARSEARRAYS_TAR_URL = https://api.github.com/repos/JuliaSparse/SparseArrays.jl/tarball/$1 diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index 95cd1ecccd9c3..b9be89826cd20 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -1268,6 +1268,9 @@ when they all pass (the default is `false`). - `showtiming`: if `true`, the duration of each displayed testset is shown (the default is `true`). +!!! compat "Julia 1.8" + `@testset foo()` requires at least Julia 1.8. + The description string accepts interpolation from the loop indices. If no description is provided, one is constructed based on the variables. If a function call is provided, its name will be used. Explicit description strings override this behavior. diff --git a/test/abstractarray.jl b/test/abstractarray.jl index f504af8a08247..9d301f0eaa64b 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -525,6 +525,10 @@ function test_primitives(::Type{T}, shape, ::Type{TestAbstractArray}) where T @test_throws MethodError convert(Union{}, X) end +@testset "CanonicalIndexError is a Exception" begin + @test Base.CanonicalIndexError <: Exception +end + mutable struct TestThrowNoGetindex{T} <: AbstractVector{T} end @testset "ErrorException if getindex is not defined" begin Base.length(::TestThrowNoGetindex) = 2 diff --git a/test/arrayops.jl b/test/arrayops.jl index 22d38fddd3636..7587b176a0deb 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -761,6 +761,18 @@ end @test circshift(src, 1) == src src = zeros(Bool, (4,0)) @test circshift(src, 1) == src + + # 1d circshift! (https://github.com/JuliaLang/julia/issues/46533) + a = [1:5;] + @test circshift!(a, 1) === a + @test a == circshift([1:5;], 1) == [5, 1, 2, 3, 4] + a = [1:5;] + @test circshift!(a, -2) === a + @test a == circshift([1:5;], -2) == [3, 4, 5, 1, 2] + a = [1:5;] + oa = OffsetVector(copy(a), -1) + @test circshift!(oa, 1) === oa + @test oa == circshift(OffsetVector(a, -1), 1) end @testset "circcopy" begin diff --git a/test/ccall.jl b/test/ccall.jl index 3a1b6ff3db733..f0d240aad342d 100644 --- a/test/ccall.jl +++ b/test/ccall.jl @@ -1590,6 +1590,32 @@ function caller22734(ptr) end @test caller22734(ptr22734) === 32.0 +# issue #46786 -- non-isbitstypes passed "by-value" +struct NonBits46786 + x::Union{Int16,NTuple{3,UInt8}} +end +let ptr = @cfunction(identity, NonBits46786, (NonBits46786,)) + obj1 = NonBits46786((0x01,0x02,0x03)) + obj2 = ccall(ptr, NonBits46786, (NonBits46786,), obj1) + @test obj1 === obj2 +end +let ptr = @cfunction(identity, Base.RefValue{NonBits46786}, (Base.RefValue{NonBits46786},)) + obj1 = Base.RefValue(NonBits46786((0x01,0x02,0x03))) + obj2 = ccall(ptr, Base.RefValue{NonBits46786}, (Base.RefValue{NonBits46786},), obj1) + @test obj1 !== obj2 + @test obj1.x === obj2.x +end + +mutable struct MutNonBits46786 + x::Union{Int16,NTuple{3,UInt8}} +end +let ptr = @cfunction(identity, MutNonBits46786, (MutNonBits46786,)) + obj1 = MutNonBits46786((0x01,0x02,0x03)) + obj2 = ccall(ptr, MutNonBits46786, (MutNonBits46786,), obj1) + @test obj1 !== obj2 + @test obj1.x === obj2.x +end + # 26297#issuecomment-371165725 # test that the first argument to cglobal is recognized as a tuple literal even through # macro expansion diff --git a/test/llvmpasses/alloc-opt-unsized.ll b/test/llvmpasses/alloc-opt-unsized.ll new file mode 100644 index 0000000000000..f7ea31fde6b05 --- /dev/null +++ b/test/llvmpasses/alloc-opt-unsized.ll @@ -0,0 +1,35 @@ +; RUN: opt -enable-new-pm=0 -load libjulia-codegen%shlibext -AllocOpt -S %s | FileCheck %s + +source_filename = "text" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128-ni:10:11:12:13" +target triple = "x86_64-linux-gnu" + +declare {}*** @julia.get_pgcstack() + +declare {} addrspace(10)* @julia.gc_alloc_obj({}**, i64, {} addrspace(10)*) + +declare void @julia.write_barrier({} addrspace(10)*, ...) + +define void @diffejulia_objective__1864_inner_1wrap({} addrspace(10)* %arg, i64 %iv.i) { +entry: + %i5 = call {}*** @julia.get_pgcstack() + %i13 = bitcast {}*** %i5 to {}** + %i14 = getelementptr inbounds {}*, {}** %i13, i64 -12 + %i18 = call noalias nonnull dereferenceable(8000) dereferenceable_or_null(8000) {} addrspace(10)* @julia.gc_alloc_obj({}** %i14, i64 8000, {} addrspace(10)* addrspacecast ({}* inttoptr (i64 139756155247504 to {}*) to {} addrspace(10)*)) + %_malloccache.i = bitcast {} addrspace(10)* %i18 to {} addrspace(10)* addrspace(10)* + %i23 = getelementptr inbounds {} addrspace(10)*, {} addrspace(10)* addrspace(10)* %_malloccache.i, i64 %iv.i + store {} addrspace(10)* %arg, {} addrspace(10)* addrspace(10)* %i23, align 8 + %i24 = bitcast {} addrspace(10)* addrspace(10)* %_malloccache.i to {} addrspace(10)* + call void ({} addrspace(10)*, ...) @julia.write_barrier({} addrspace(10)* %i24, {} addrspace(10)* %arg) + %l = load {} addrspace(10)*, {} addrspace(10)* addrspace(10)* %i23 + ret void +} + +; CHECK: %[[i0:.+]] = alloca {} addrspace(10)*, i64 1000, align 16 +; CHECK: %[[i1:.+]] = bitcast {} addrspace(10)** %[[i0]] to i8* +; CHECK: %i18 = bitcast i8* %[[i1]] to {}* +; CHECK: %_malloccache.i = bitcast {}* %i18 to {} addrspace(10)** +; CHECK: %i23 = getelementptr inbounds {} addrspace(10)*, {} addrspace(10)** %_malloccache.i, i64 %iv.i +; CHECK: store {} addrspace(10)* %arg, {} addrspace(10)** %i23, align 8 +; CHECK: %i24 = bitcast {} addrspace(10)** %_malloccache.i to {}* +; CHECK: %l = load {} addrspace(10)*, {} addrspace(10)** %i23, align 8 diff --git a/test/llvmpasses/late-lower-gc.ll b/test/llvmpasses/late-lower-gc.ll index 22cb558c54158..fb1961a3c230a 100644 --- a/test/llvmpasses/late-lower-gc.ll +++ b/test/llvmpasses/late-lower-gc.ll @@ -124,6 +124,25 @@ top: ; CHECK: ret i32 } +define void @decayar([2 x {} addrspace(10)* addrspace(11)*] %ar) { + %v2 = call {}*** @julia.get_pgcstack() + %e0 = extractvalue [2 x {} addrspace(10)* addrspace(11)*] %ar, 0 + %l0 = load {} addrspace(10)*, {} addrspace(10)* addrspace(11)* %e0 + %e1 = extractvalue [2 x {} addrspace(10)* addrspace(11)*] %ar, 1 + %l1 = load {} addrspace(10)*, {} addrspace(10)* addrspace(11)* %e1 + %r = call i32 @callee_root({} addrspace(10)* %l0, {} addrspace(10)* %l1) + ret void +} + +; CHECK-LABEL: @decayar +; CHECK: %gcframe = call {} addrspace(10)** @julia.new_gc_frame(i32 2) +; CHECK: %1 = call {} addrspace(10)** @julia.get_gc_frame_slot({} addrspace(10)** %gcframe, i32 1) +; CHECK: store {} addrspace(10)* %l0, {} addrspace(10)** %1, align 8 +; CHECK: %2 = call {} addrspace(10)** @julia.get_gc_frame_slot({} addrspace(10)** %gcframe, i32 0) +; CHECK: store {} addrspace(10)* %l1, {} addrspace(10)** %2, align 8 +; CHECK: %r = call i32 @callee_root({} addrspace(10)* %l0, {} addrspace(10)* %l1) +; CHECK: call void @julia.pop_gc_frame({} addrspace(10)** %gcframe) + !0 = !{i64 0, i64 23} !1 = !{} !2 = distinct !{!2} diff --git a/test/operators.jl b/test/operators.jl index 1c5d2d33bf0f8..432456a2a3b42 100644 --- a/test/operators.jl +++ b/test/operators.jl @@ -261,6 +261,9 @@ end end @test fldmod1(4.0, 3) == fldmod1(4, 3) + + # issue 28973 + @test fld1(0.4, 0.9) == fld1(nextfloat(0.4), 0.9) == 1.0 end @testset "Fix12" begin diff --git a/test/precompile.jl b/test/precompile.jl index a8937581cb5d0..072d0ba694699 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -1290,3 +1290,20 @@ precompile_test_harness("__init__ cachepath") do load_path """) @test isa((@eval (using InitCachePath; InitCachePath)), Module) end + +precompile_test_harness("issue #46296") do load_path + write(joinpath(load_path, "CodeInstancePrecompile.jl"), + """ + module CodeInstancePrecompile + + mi = first(methods(identity)).specializations[1] + ci = Core.CodeInstance(mi, Any, nothing, nothing, zero(Int32), typemin(UInt), + typemax(UInt), zero(UInt32), zero(UInt32), nothing, 0x00) + + __init__() = @assert ci isa Core.CodeInstance + + end + """) + Base.compilecache(Base.PkgId("CodeInstancePrecompile")) + (@eval (using CodeInstancePrecompile)) +end diff --git a/test/ranges.jl b/test/ranges.jl index c448f4b99e201..b68ab3312f304 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -518,8 +518,10 @@ end @test !(3.5 in 1:5) @test (3 in 1:5) @test (3 in 5:-1:1) - #@test (3 in 3+0*(1:5)) - #@test !(4 in 3+0*(1:5)) + @test (3 in 3 .+ 0*(1:5)) + @test !(4 in 3 .+ 0*(1:5)) + @test 0. in (0. .* (1:10)) + @test !(0.1 in (0. .* (1:10))) let r = 0.0:0.01:1.0 @test (r[30] in r) @@ -536,8 +538,17 @@ end x = (NaN16, Inf32, -Inf64, 1//0, -1//0) @test !(x in r) end + + @test 1e40 ∉ 0:1.0 # Issue #45747 + @test 1e20 ∉ 0:1e-20:1e-20 + @test 1e20 ∉ 0:1e-20 + @test 1.0 ∉ 0:1e-20:1e-20 + @test 0.5 ∉ 0:1e-20:1e-20 + @test 1 ∉ 0:1e-20:1e-20 + + @test_broken 17.0 ∈ 0:1e40 # Don't support really long ranges end - @testset "in() works across types, including non-numeric types (#21728)" begin + @testset "in() works across types, including non-numeric types (#21728 and #45646)" begin @test 1//1 in 1:3 @test 1//1 in 1.0:3.0 @test !(5//1 in 1:3) @@ -558,6 +569,22 @@ end @test !(Complex(1, 0) in Date(2017, 01, 01):Dates.Day(1):Date(2017, 01, 05)) @test !(π in Date(2017, 01, 01):Dates.Day(1):Date(2017, 01, 05)) @test !("a" in Date(2017, 01, 01):Dates.Day(1):Date(2017, 01, 05)) + + # We use Ducks because of their propensity to stand in a row and because we know + # that no additional methods (e.g. isfinite) are defined specifically for Ducks. + struct Duck + location::Int + end + Base.:+(x::Duck, y::Int) = Duck(x.location + y) + Base.:-(x::Duck, y::Int) = Duck(x.location - y) + Base.:-(x::Duck, y::Duck) = x.location - y.location + Base.isless(x::Duck, y::Duck) = isless(x.location, y.location) + + @test Duck(3) ∈ Duck(1):2:Duck(5) + @test Duck(3) ∈ Duck(5):-2:Duck(2) + @test Duck(4) ∉ Duck(5):-2:Duck(1) + @test Duck(4) ∈ Duck(1):Duck(5) + @test Duck(0) ∉ Duck(1):Duck(5) end end @testset "indexing range with empty range (#4309)" begin diff --git a/test/show.jl b/test/show.jl index ba9f227e53e52..70dd9db898e75 100644 --- a/test/show.jl +++ b/test/show.jl @@ -2355,3 +2355,16 @@ end @test sprint(show, setenv(setcpuaffinity(`true`, [1, 2]), "A" => "B")) == """setenv(setcpuaffinity(`true`, [1, 2]),["A=B"])""" end + +# Test that alignment takes into account unicode and computes alignment without +# color/formatting. + +struct ColoredLetter; end +Base.show(io::IO, ces::ColoredLetter) = Base.printstyled(io, 'A'; color=:red) + +struct ⛵; end +Base.show(io::IO, ces::⛵) = Base.print(io, '⛵') + +@test Base.alignment(stdout, ⛵()) == (0, 2) +@test Base.alignment(IOContext(IOBuffer(), :color=>true), ColoredLetter()) == (0, 1) +@test Base.alignment(IOContext(IOBuffer(), :color=>false), ColoredLetter()) == (0, 1) diff --git a/test/subtype.jl b/test/subtype.jl index 5bb2037d7852b..c6d2dada81d25 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -2031,3 +2031,12 @@ S46735{B<:Val, M<:AbstractMatrix} = Tuple{<:Union{B, <:Val{<:B}},M,<:(Union{Abst A46735{B<:Val, M<:AbstractMatrix} = Tuple{<:Union{B, <:Val{<:B}},M,Union{AbstractMatrix{B}, AbstractMatrix{<:Vector{<:B}}}} @testintersect(A46735{B} where {B}, A46735, !Union{}) @testintersect(A46735{B, M} where {B, M}, A46735, !Union{}) + +#issue #46871 +struct A46871{T, N, M} <: AbstractArray{T, N} end +struct B46871{T, N} <: Ref{A46871{T, N, N}} end +for T in (B46871{Int, N} where {N}, B46871{Int}) # intentional duplication + @testintersect(T, Ref{<:AbstractArray{<:Real, 3}}, B46871{Int, 3}) +end + +@test !(Tuple{Any, Any, Any} <: Tuple{Any, Vararg{T}} where T)