From 949412520e287803eef0d090ccacbe5a9a877f10 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Thu, 11 Dec 2025 14:05:18 +0100 Subject: [PATCH 01/83] set VERSION to 1.12.3 (#60346) --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 6b89d58f861a7..81f363239f557 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.12.2 +1.12.3 From 966d0af0fdffc727eb240e2e4c908fdd46697e57 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Mon, 15 Dec 2025 12:20:38 +0100 Subject: [PATCH 02/83] release-1.12: Revert "build: More msys2 fixes (#59028)" (#60374) --- contrib/mac/app/Makefile | 4 ++-- deps/libgit2.mk | 11 +---------- deps/libssh2.mk | 5 ++++- deps/libuv.mk | 2 +- deps/llvm.mk | 8 -------- deps/openssl.mk | 18 ++++++++++-------- deps/tools/common.mk | 24 ++---------------------- src/Makefile | 12 +++++------- src/flisp/Makefile | 2 +- 9 files changed, 26 insertions(+), 60 deletions(-) diff --git a/contrib/mac/app/Makefile b/contrib/mac/app/Makefile index 70436a857c265..81b7e47cdf2cf 100644 --- a/contrib/mac/app/Makefile +++ b/contrib/mac/app/Makefile @@ -47,8 +47,8 @@ dmg/$(APP_NAME): startup.applescript julia.icns plutil -insert CFBundleVersion -string "$(JULIA_VERSION_OPT_COMMIT)" $@/Contents/Info.plist plutil -insert NSHumanReadableCopyright -string "$(APP_COPYRIGHT)" $@/Contents/Info.plist -mkdir -p $@/Contents/Resources/julia - $(MAKE) -C $(JULIAHOME) binary-dist - $(TAR) -xzf $(JULIAHOME)/$(JULIA_BINARYDIST_FILENAME).tar.gz -C $@/Contents/Resources/julia --strip-components 1 + make -C $(JULIAHOME) binary-dist + tar zxf $(JULIAHOME)/$(JULIA_BINARYDIST_FILENAME).tar.gz -C $@/Contents/Resources/julia --strip-components 1 find $@/Contents/Resources/julia -type f -exec chmod -w {} \; # Even though the tarball may already be signed, we re-sign here to make it easier to add # unsigned executables (like the app launcher) and whatnot, without needing to maintain lists diff --git a/deps/libgit2.mk b/deps/libgit2.mk index dd0d883c2e736..8b17ae6d70424 100644 --- a/deps/libgit2.mk +++ b/deps/libgit2.mk @@ -4,7 +4,6 @@ ifneq ($(USE_BINARYBUILDER_LIBGIT2),1) LIBGIT2_GIT_URL := https://github.com/libgit2/libgit2.git LIBGIT2_TAR_URL = https://api.github.com/repos/libgit2/libgit2/tarball/$1 $(eval $(call git-external,libgit2,LIBGIT2,CMakeLists.txt,,$(SRCCACHE))) -$(SRCCACHE)/$(LIBGIT2_SRC_DIR)/source-extracted: $(MSYS_NONEXISTENT_SYMLINK_TARGET_FIX) ifeq ($(USE_SYSTEM_LIBSSH2), 0) $(BUILDDIR)/$(LIBGIT2_SRC_DIR)/build-configured: | $(build_prefix)/manifest/libssh2 @@ -14,15 +13,7 @@ ifeq ($(USE_SYSTEM_OPENSSL), 0) $(BUILDDIR)/$(LIBGIT2_SRC_DIR)/build-configured: | $(build_prefix)/manifest/openssl endif -ifeq ($(USE_SYSTEM_PCRE), 0) -$(BUILDDIR)/$(LIBGIT2_SRC_DIR)/build-configured: | $(build_prefix)/manifest/pcre -endif - -ifeq ($(USE_SYSTEM_ZLIB), 0) -$(BUILDDIR)/$(LIBGIT2_SRC_DIR)/build-configured: | $(build_prefix)/manifest/zlib -endif - -LIBGIT2_OPTS := $(CMAKE_COMMON) -DCMAKE_BUILD_TYPE=Release -DUSE_THREADS=ON -DUSE_BUNDLED_ZLIB=OFF -DUSE_SSH=ON -DREGEX_BACKEND=pcre2 -DBUILD_CLI=OFF -DBUILD_TESTS=OFF +LIBGIT2_OPTS := $(CMAKE_COMMON) -DCMAKE_BUILD_TYPE=Release -DUSE_THREADS=ON -DUSE_BUNDLED_ZLIB=ON -DUSE_SSH=ON -DBUILD_CLI=OFF ifeq ($(OS),WINNT) LIBGIT2_OPTS += -DWIN32=ON -DMINGW=ON ifeq ($(USE_SYSTEM_LIBSSH2), 0) diff --git a/deps/libssh2.mk b/deps/libssh2.mk index 05cc12b6e159b..661e26516c828 100644 --- a/deps/libssh2.mk +++ b/deps/libssh2.mk @@ -17,6 +17,9 @@ endif ifeq ($(OS),WINNT) LIBSSH2_OPTS += -DCRYPTO_BACKEND=WinCNG -DENABLE_ZLIB_COMPRESSION=OFF +ifeq ($(BUILD_OS),WINNT) +LIBSSH2_OPTS += -G"MSYS Makefiles" +endif else LIBSSH2_OPTS += -DCRYPTO_BACKEND=OpenSSL -DENABLE_ZLIB_COMPRESSION=OFF LIBSSH2_OPTS += -DOPENSSL_ROOT_DIR=$(build_prefix) @@ -35,7 +38,7 @@ LIBSSH2_SRC_PATH := $(SRCCACHE)/$(LIBSSH2_SRC_DIR) $(BUILDDIR)/$(LIBSSH2_SRC_DIR)/build-configured: $(LIBSSH2_SRC_PATH)/source-extracted mkdir -p $(dir $@) cd $(dir $@) && \ - $(CMAKE) $(CMAKE_GENERATOR_COMMAND) $(dir $<) $(LIBSSH2_OPTS) + $(CMAKE) $(dir $<) $(LIBSSH2_OPTS) echo 1 > $@ $(BUILDDIR)/$(LIBSSH2_SRC_DIR)/build-compiled: $(BUILDDIR)/$(LIBSSH2_SRC_DIR)/build-configured diff --git a/deps/libuv.mk b/deps/libuv.mk index 993aa4fc144da..eacabac55e34f 100644 --- a/deps/libuv.mk +++ b/deps/libuv.mk @@ -4,7 +4,7 @@ LIBUV_GIT_URL:=https://github.com/JuliaLang/libuv.git LIBUV_TAR_URL=https://api.github.com/repos/JuliaLang/libuv/tarball/$1 $(eval $(call git-external,libuv,LIBUV,configure,,$(SRCCACHE))) -UV_CFLAGS := -O2 -DBUILDING_UV_SHARED=1 +UV_CFLAGS := -O2 UV_FLAGS := LDFLAGS="$(LDFLAGS) $(CLDFLAGS) -v" UV_FLAGS += CFLAGS="$(CFLAGS) $(UV_CFLAGS) $(SANITIZE_OPTS)" diff --git a/deps/llvm.mk b/deps/llvm.mk index 8b823b8664bf2..09dd4f187d611 100644 --- a/deps/llvm.mk +++ b/deps/llvm.mk @@ -7,14 +7,6 @@ ifneq ($(USE_BINARYBUILDER_LLVM), 1) LLVM_GIT_URL:=https://github.com/JuliaLang/llvm-project.git LLVM_TAR_URL=https://api.github.com/repos/JuliaLang/llvm-project/tarball/$1 $(eval $(call git-external,llvm,LLVM,CMakeLists.txt,,$(SRCCACHE))) -# LLVM's tarball contains symlinks to non-existent targets. This breaks the -# the default msys strategy `deepcopy` symlink strategy. To workaround this, -# switch to `native` which tries native windows symlinks (possible if the -# machine is in developer mode) - or if not, falls back to cygwin-style -# symlinks. We don't particularly care either way - we just need to symlinks -# to succeed. We could guard this by a uname check, but it's harmless elsewhere, -# so let's not incur the additional overhead. -$(SRCCACHE)/$(LLVM_SRC_DIR)/source-extracted: $(MSYS_NONEXISTENT_SYMLINK_TARGET_FIX) LLVM_BUILDDIR := $(BUILDDIR)/$(LLVM_SRC_DIR) LLVM_BUILDDIR_withtype := $(LLVM_BUILDDIR)/build_$(LLVM_BUILDTYPE) diff --git a/deps/openssl.mk b/deps/openssl.mk index 734ddb3274e78..705303432c2c6 100644 --- a/deps/openssl.mk +++ b/deps/openssl.mk @@ -59,7 +59,7 @@ $(BUILDDIR)/openssl-$(OPENSSL_VER)/build-configured: $(SRCCACHE)/openssl-$(OPENS mkdir -p $(dir $@) cd $(dir $@) && \ CC="$(CC) $(SANITIZE_OPTS)" CXX="$(CXX) $(SANITIZE_OPTS)" LDFLAGS="$(LDFLAGS) $(RPATH_ESCAPED_ORIGIN) $(SANITIZE_LDFLAGS)" \ - $(dir $<)/Configure shared --prefix=$(abspath $(build_prefix)) --libdir=$(abspath $(build_libdir)) $(OPENSSL_TARGET) + $(dir $<)/Configure shared --prefix=$(abspath $(build_prefix)) $(OPENSSL_TARGET) echo 1 > $@ $(BUILDDIR)/openssl-$(OPENSSL_VER)/build-compiled: $(BUILDDIR)/openssl-$(OPENSSL_VER)/build-configured @@ -75,16 +75,18 @@ endif # Override bindir and only install runtime libraries, otherwise they'll go into build_depsbindir. OPENSSL_INSTALL = \ mkdir -p $2$$(build_shlibdir) && \ - $$(MAKE) -C $1 install_runtime_libs $$(MAKE_COMMON) bindir=$$(build_shlibdir) $3 DESTDIR="$2" + $$(MAKE) -C $1 install_dev $$(MAKE_COMMON) bindir=$$(build_shlibdir) $3 DESTDIR="$2" + +OPENSSL_POST_INSTALL := \ + $(WIN_MAKE_HARD_LINK) $(build_bindir)/libcrypto-*.dll $(build_bindir)/libcrypto.dll && \ + $(WIN_MAKE_HARD_LINK) $(build_bindir)/libssl-*.dll $(build_bindir)/libssl.dll && \ + $(INSTALL_NAME_CMD)libcrypto.$(SHLIB_EXT) $(build_shlibdir)/libcrypto.$(SHLIB_EXT) && \ + $(INSTALL_NAME_CMD)libssl.$(SHLIB_EXT) $(build_shlibdir)/libssl.$(SHLIB_EXT) && \ + $(INSTALL_NAME_CHANGE_CMD) $(build_shlibdir)/libcrypto.3.dylib @rpath/libcrypto.$(SHLIB_EXT) $(build_shlibdir)/libssl.$(SHLIB_EXT) $(eval $(call staged-install, \ openssl,openssl-$(OPENSSL_VER), \ - OPENSSL_INSTALL,,, \ - $$(WIN_MAKE_HARD_LINK) $(build_bindir)/libcrypto-*.dll $(build_bindir)/libcrypto.dll && \ - $$(WIN_MAKE_HARD_LINK) $(build_bindir)/libssl-*.dll $(build_bindir)/libssl.dll && \ - $$(INSTALL_NAME_CMD)libcrypto.$$(SHLIB_EXT) $$(build_shlibdir)/libcrypto.$$(SHLIB_EXT) && \ - $$(INSTALL_NAME_CMD)libssl.$$(SHLIB_EXT) $$(build_shlibdir)/libssl.$$(SHLIB_EXT) && \ - $$(INSTALL_NAME_CHANGE_CMD) $$(build_shlibdir)/libcrypto.3.dylib @rpath/libcrypto.$$(SHLIB_EXT) $$(build_shlibdir)/libssl.$$(SHLIB_EXT))) + OPENSSL_INSTALL,,,$(OPENSSL_POST_INSTALL))) clean-openssl: -rm -f $(BUILDDIR)/-openssl-$(OPENSSL_VER)/build-configured $(BUILDDIR)/-openssl-$(OPENSSL_VER)/build-compiled diff --git a/deps/tools/common.mk b/deps/tools/common.mk index 212b576fb63f9..01b57316f9d1a 100644 --- a/deps/tools/common.mk +++ b/deps/tools/common.mk @@ -59,6 +59,7 @@ CMAKE_COMMON += -DCMAKE_SYSTEM_NAME=Windows CMAKE_COMMON += -DCMAKE_RC_COMPILER="$$(which $(CROSS_COMPILE)windres)" endif +# For now this is LLVM specific, but I expect it won't be in the future ifeq ($(CMAKE_GENERATOR),Ninja) CMAKE_GENERATOR_COMMAND := -G Ninja else ifeq ($(CMAKE_GENERATOR),make) @@ -67,27 +68,6 @@ else $(error Unknown CMake generator '$(CMAKE_GENERATOR)'. Options are 'Ninja' and 'make') endif -ifneq (,$(findstring MINGW,$(RAW_BUILD_OS))) -ifneq (,$(shell ldd $(shell which cmake) | grep msys-2.0.dll)) -# Detect MSYS2 with cygwin CMake rather than MinGW cmake - the former fails to -# properly drive MinGW tools -override CMAKE := echo "ERROR: CMake is Cygwin CMake, not MinGW CMake. Build will fail. Use 'pacman -S mingw-w64-{i686,x86_64}-cmake'."; exit 1; $(CMAKE) -endif -# In our setup, CMAKE_INSTALL_PREFIX is a relative path inside usr-staging. -# We do not want this converted to a windows path, because our make system -# assumes it to be relative to msys `/`. -override CMAKE := MSYS2_ARG_CONV_EXCL="-DCMAKE_INSTALL_PREFIX" $(CMAKE) -endif - -# Some dependencies' tarballs contains symlinks to non-existent targets. This breaks the -# the default msys strategy `deepcopy` symlink strategy. To workaround this, -# switch to `native` which tries native windows symlinks (possible if the -# machine is in developer mode) - or if not, falls back to cygwin-style -# symlinks. We don't particularly care either way - we just need to symlinks -# to succeed. We could guard this by a uname check, but it's harmless elsewhere, -# so let's not incur the additional overhead. -MSYS_NONEXISTENT_SYMLINK_TARGET_FIX := export MSYS=winsymlinks:native - # If the top-level Makefile is called with environment variables, # they will override the values passed above to ./configure MAKE_COMMON := DESTDIR="" prefix=$(build_prefix) bindir=$(build_depsbindir) libdir=$(build_libdir) shlibdir=$(build_shlibdir) libexecdir=$(build_libexecdir) datarootdir=$(build_datarootdir) includedir=$(build_includedir) sysconfdir=$(build_sysconfdir) O= @@ -164,7 +144,7 @@ upper = $(shell echo $1 | tr a-z A-Z) # this rule ensures that make install is more nearly atomic # so it's harder to get half-installed (or half-reinstalled) dependencies # # and enables sharing deps compiles, uninstall, and fast reinstall -MAKE_INSTALL = MSYS2_ARG_CONV_EXCL="prefix=" $$(MAKE) -C $1 install $$(MAKE_COMMON) $3 DESTDIR="$2" +MAKE_INSTALL = +$$(MAKE) -C $1 install $$(MAKE_COMMON) $3 DESTDIR="$2" define SHLIBFILE_INSTALL mkdir -p $2/$$(build_shlibdir) diff --git a/src/Makefile b/src/Makefile index 6245139592db1..e859acc765354 100644 --- a/src/Makefile +++ b/src/Makefile @@ -75,7 +75,7 @@ GC_CODEGEN_SRCS += llvm-late-gc-lowering-stock endif CODEGEN_SRCS := codegen jitlayers aotcompile debuginfo disasm llvm-simdloop \ llvm-pass-helpers llvm-ptls \ - llvm-lower-handlers llvm-propagate-addrspaces \ + llvm-lower-handlers llvm-propagate-addrspaces null_sysimage \ llvm-multiversioning llvm-alloc-opt llvm-alloc-helpers cgmemmgr llvm-remove-addrspaces \ llvm-remove-ni llvm-julia-licm llvm-demote-float16 llvm-cpufeatures pipeline llvm_api \ $(GC_CODEGEN_SRCS) @@ -192,9 +192,7 @@ endif COMMON_LIBPATHS := -L$(build_libdir) -L$(build_shlibdir) RT_LIBS := $(WHOLE_ARCHIVE) $(LIBUV) $(WHOLE_ARCHIVE) $(LIBUTF8PROC) $(NO_WHOLE_ARCHIVE) $(LIBUNWIND) $(RT_LLVMLINK) $(OSLIBS) $(LIBTRACYCLIENT) $(LIBITTAPI) $(MMTK_LIB) -# NB: CG needs uv_mutex_* symbols, but we expect to export them from libjulia-internal CG_LIBS := $(LIBUNWIND) $(CG_LLVMLINK) $(OSLIBS) $(LIBTRACYCLIENT) $(LIBITTAPI) $(MMTK_LIB) - 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) $(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) @@ -471,10 +469,10 @@ libjulia-codegen-debug: $(build_shlibdir)/libjulia-codegen-debug.$(JL_MAJOR_MINO libjulia-codegen-debug libjulia-codegen-release: $(PUBLIC_HEADER_TARGETS) # set the exports for the source files based on where they are getting linked -$(OBJS): SHIPFLAGS += -DJL_LIBRARY_EXPORTS_INTERNAL -DBUILDING_UV_SHARED -$(DOBJS): DEBUGFLAGS += -DJL_LIBRARY_EXPORTS_INTERNAL -DBUILDING_UV_SHARED -$(CODEGEN_OBJS): SHIPFLAGS += -DJL_LIBRARY_EXPORTS_CODEGEN -DUSING_UV_SHARED -$(CODEGEN_DOBJS): DEBUGFLAGS += -DJL_LIBRARY_EXPORTS_CODEGEN -DUSING_UV_SHARED +$(OBJS): SHIPFLAGS += -DJL_LIBRARY_EXPORTS_INTERNAL +$(DOBJS): DEBUGFLAGS += -DJL_LIBRARY_EXPORTS_INTERNAL +$(CODEGEN_OBJS): SHIPFLAGS += -DJL_LIBRARY_EXPORTS_CODEGEN +$(CODEGEN_DOBJS): DEBUGFLAGS += -DJL_LIBRARY_EXPORTS_CODEGEN clean: -rm -fr $(build_shlibdir)/libjulia-internal* $(build_shlibdir)/libjulia-codegen* $(build_shlibdir)/libccalltest* $(build_shlibdir)/libllvmcalltest* diff --git a/src/flisp/Makefile b/src/flisp/Makefile index 2e902a31dbeed..eca1de86e588a 100644 --- a/src/flisp/Makefile +++ b/src/flisp/Makefile @@ -117,7 +117,7 @@ $(BUILDDIR)/host/Makefile: @printf "%s\n" 'include $(SRCDIR)/Makefile' >> $@ $(BUILDDIR)/host/$(EXENAME): $(BUILDDIR)/host/Makefile | ${BUILDDIR}/host/flisp.boot - $(MAKE) -C $(BUILDDIR)/host $(EXENAME) + make -C $(BUILDDIR)/host $(EXENAME) $(BUILDDIR)/host/flisp.boot: $(SRCDIR)/flisp.boot | $(BUILDDIR)/host/Makefile From 120dad24b56ff6478fdb93c62acd35eebcaa71dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= <765740+giordano@users.noreply.github.com> Date: Sat, 29 Nov 2025 08:00:21 +0000 Subject: [PATCH 03/83] Correct version in which at-lock was exported (#60279) It was exported in v1.7, not v1.10: #39588 (cherry picked from commit 1067db80b96cafb9da6864afbfdd9d6e27665c33) --- base/lock.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/lock.jl b/base/lock.jl index e74da826900a6..1feea348e5ac4 100644 --- a/base/lock.jl +++ b/base/lock.jl @@ -366,7 +366,7 @@ This is similar to using [`lock`](@ref) with a `do` block, but avoids creating a and thus can improve the performance. !!! compat - `@lock` was added in Julia 1.3, and exported in Julia 1.10. + `@lock` was added in Julia 1.3, and exported in Julia 1.7. """ macro lock(l, expr) quote From a020033531491ace3f932447f76cde681ca795cd Mon Sep 17 00:00:00 2001 From: Valentin Churavy Date: Tue, 2 Dec 2025 18:32:18 +0100 Subject: [PATCH 04/83] Fix buffer overflow in jloptions (#60299) Co-authored-by: Cody Tapscott <84105208+topolarity@users.noreply.github.com> (cherry picked from commit 841148d8a81066c4d4b93fac2f2d32aacad05fa7) --- src/jloptions.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/jloptions.c b/src/jloptions.c index 96cce1c8d29a3..bb4092bb2845d 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -668,9 +668,11 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) } jl_options.nthreads = nthreads + nthreadsi; } + assert(jl_options.nthreadpools == 1 || jl_options.nthreadpools == 2); int16_t *ntpp = (int16_t *)malloc_s(jl_options.nthreadpools * sizeof(int16_t)); ntpp[0] = (int16_t)nthreads; - ntpp[1] = (int16_t)nthreadsi; + if (jl_options.nthreadpools == 2) + ntpp[1] = (int16_t)nthreadsi; jl_options.nthreads_per_pool = ntpp; break; case 'p': // procs From 986bb5ea6021006f9af38e441f4c8b6d0e4a2807 Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Tue, 2 Dec 2025 15:55:14 -0500 Subject: [PATCH 05/83] build: include `SuiteSparse` in pkgimages to precompile (#60291) This seems to be an issue at least as far back as 1.10: ```julia $ rm -rf ~/.julia/compiled/*/SuiteSparse/ $ julia +1.10 -q julia> using SuiteSparse [ Info: Precompiling SuiteSparse [4607b0f0-06f3-5cda-b6b1-a6196a1729e9] ``` (cherry picked from commit d6f2a7e32e0991637e2e2f696c23494b75201a99) --- stdlib/Manifest.toml | 5 +++++ stdlib/Project.toml | 1 + stdlib/stdlib.mk | 4 ++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/stdlib/Manifest.toml b/stdlib/Manifest.toml index 3db51cf75328d..14482fd3001b6 100644 --- a/stdlib/Manifest.toml +++ b/stdlib/Manifest.toml @@ -240,6 +240,11 @@ weakdeps = ["SparseArrays"] uuid = "f489334b-da3d-4c2e-b8f0-e476e12c162b" version = "1.11.0" +[[deps.SuiteSparse]] +deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] +uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" +version = "1.12.0" + [[deps.SuiteSparse_jll]] deps = ["Artifacts", "Libdl", "libblastrampoline_jll"] uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" diff --git a/stdlib/Project.toml b/stdlib/Project.toml index 1e03a0f474490..8a3e0f4d78e69 100644 --- a/stdlib/Project.toml +++ b/stdlib/Project.toml @@ -48,6 +48,7 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" StyledStrings = "f489334b-da3d-4c2e-b8f0-e476e12c162b" SuiteSparse_jll = "bea87d4a-7f5b-5778-9afe-8cc45184846c" +SuiteSparse = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76" Tar = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/stdlib/stdlib.mk b/stdlib/stdlib.mk index 006b7a276a3b3..1c418a7e1a8f4 100644 --- a/stdlib/stdlib.mk +++ b/stdlib/stdlib.mk @@ -6,8 +6,8 @@ INDEPENDENT_STDLIBS := \ ArgTools Base64 CRC32c Dates DelimitedFiles Distributed Downloads Future \ InteractiveUtils JuliaSyntaxHighlighting LazyArtifacts LibGit2 LibCURL Logging \ Markdown Mmap NetworkOptions Profile Printf Pkg REPL Serialization SharedArrays \ - SparseArrays Statistics StyledStrings SuiteSparse_jll Tar Test TOML Unicode UUIDs \ - dSFMT_jll GMP_jll libLLVM_jll LLD_jll LLVMLibUnwind_jll LibUnwind_jll LibUV_jll \ + SparseArrays Statistics StyledStrings SuiteSparse_jll SuiteSparse Tar Test TOML \ + Unicode UUIDs dSFMT_jll GMP_jll libLLVM_jll LLD_jll LLVMLibUnwind_jll LibUnwind_jll LibUV_jll \ LibCURL_jll LibSSH2_jll LibGit2_jll nghttp2_jll MozillaCACerts_jll \ MPFR_jll OpenLibm_jll OpenSSL_jll PCRE2_jll p7zip_jll Zlib_jll From e35b957bb5caffeb1af708184714c9f99484a6d1 Mon Sep 17 00:00:00 2001 From: Eddie Groshev Date: Tue, 9 Dec 2025 23:33:24 -0800 Subject: [PATCH 06/83] Logging: define isless between Integer and LogLevel (#60330) (cherry picked from commit 5ee081631674166af22f3677d50c2fd56a2ccf48) --- base/logging/logging.jl | 2 ++ stdlib/Logging/test/runtests.jl | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/base/logging/logging.jl b/base/logging/logging.jl index c44e74ffa627b..bb24a0e47b05b 100644 --- a/base/logging/logging.jl +++ b/base/logging/logging.jl @@ -129,6 +129,8 @@ end LogLevel(level::LogLevel) = level isless(a::LogLevel, b::LogLevel) = isless(a.level, b.level) +isless(a::LogLevel, b::Integer) = isless(a.level, b) +isless(a::Integer, b::LogLevel) = isless(a, b.level) +(level::LogLevel, inc::Integer) = LogLevel(level.level+inc) -(level::LogLevel, inc::Integer) = LogLevel(level.level-inc) convert(::Type{LogLevel}, level::Integer) = LogLevel(level) diff --git a/stdlib/Logging/test/runtests.jl b/stdlib/Logging/test/runtests.jl index 3e92b7d9e2697..a0ba9f7c43b1e 100644 --- a/stdlib/Logging/test/runtests.jl +++ b/stdlib/Logging/test/runtests.jl @@ -19,6 +19,13 @@ macro customlog(exs...) Base.CoreLogging.logmsg_code((Base.CoreLogging.@_sourcei @test :handle_message in names(Logging, all=true) # non-exported public function end +@testset "LogLevel compatibility with integers" begin + @test Logging.Debug + 1000 == Logging.Info + @test Logging.Warn - 1000 == Logging.Info + @test Logging.Info < 500 + @test 500 < Logging.Warn +end + @testset "ConsoleLogger" begin # First pass log limiting @test min_enabled_level(ConsoleLogger(devnull, Logging.Debug)) == Logging.Debug From a16e9c97f1b551916832fb399e4fab4a81dd95eb Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Tue, 16 Dec 2025 08:07:17 -0500 Subject: [PATCH 07/83] =?UTF-8?q?=F0=9F=A4=96=20[release-1.12]=20Bump=20Li?= =?UTF-8?q?nearAlgebra=20stdlib=20997c4b7=20=E2=86=92=20dd3ea72=20(#60395)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: dkarrasch <26658441+dkarrasch@users.noreply.github.com> Fix GEMM dispatch for complex-real matmul (#1520) --- .../md5 | 1 - .../sha512 | 1 - .../md5 | 1 + .../sha512 | 1 + stdlib/LinearAlgebra.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/LinearAlgebra-997c4b7e7664f30645ef8bd51d8a4203e49c4631.tar.gz/md5 delete mode 100644 deps/checksums/LinearAlgebra-997c4b7e7664f30645ef8bd51d8a4203e49c4631.tar.gz/sha512 create mode 100644 deps/checksums/LinearAlgebra-dd3ea72ec654706060220118f4a65a708733b84c.tar.gz/md5 create mode 100644 deps/checksums/LinearAlgebra-dd3ea72ec654706060220118f4a65a708733b84c.tar.gz/sha512 diff --git a/deps/checksums/LinearAlgebra-997c4b7e7664f30645ef8bd51d8a4203e49c4631.tar.gz/md5 b/deps/checksums/LinearAlgebra-997c4b7e7664f30645ef8bd51d8a4203e49c4631.tar.gz/md5 deleted file mode 100644 index 0981743e0907a..0000000000000 --- a/deps/checksums/LinearAlgebra-997c4b7e7664f30645ef8bd51d8a4203e49c4631.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -1cf83c7ea8935ac0804e07ebe8ce7506 diff --git a/deps/checksums/LinearAlgebra-997c4b7e7664f30645ef8bd51d8a4203e49c4631.tar.gz/sha512 b/deps/checksums/LinearAlgebra-997c4b7e7664f30645ef8bd51d8a4203e49c4631.tar.gz/sha512 deleted file mode 100644 index 971b146eecf64..0000000000000 --- a/deps/checksums/LinearAlgebra-997c4b7e7664f30645ef8bd51d8a4203e49c4631.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -ec3edd7208e25fb1af0b9cb2324abbfb66e556442b75df619ffdf428f1d59f851055117db896fd3514352a32c34c4c42cf50e1386deca4ebd051de98369d5a3e diff --git a/deps/checksums/LinearAlgebra-dd3ea72ec654706060220118f4a65a708733b84c.tar.gz/md5 b/deps/checksums/LinearAlgebra-dd3ea72ec654706060220118f4a65a708733b84c.tar.gz/md5 new file mode 100644 index 0000000000000..b49795485f679 --- /dev/null +++ b/deps/checksums/LinearAlgebra-dd3ea72ec654706060220118f4a65a708733b84c.tar.gz/md5 @@ -0,0 +1 @@ +89bf516f59c6e35cb0ca090d93fa347b diff --git a/deps/checksums/LinearAlgebra-dd3ea72ec654706060220118f4a65a708733b84c.tar.gz/sha512 b/deps/checksums/LinearAlgebra-dd3ea72ec654706060220118f4a65a708733b84c.tar.gz/sha512 new file mode 100644 index 0000000000000..3c87627b5a126 --- /dev/null +++ b/deps/checksums/LinearAlgebra-dd3ea72ec654706060220118f4a65a708733b84c.tar.gz/sha512 @@ -0,0 +1 @@ +286da5f2e9d6472f52e9eeee4ee9ec7b09bea8584fe95764de459b923c2323cb6ed6d9f04748c12c7f521a0a5bca07ec6ea69668e2f8e2a52595ce6a16f62410 diff --git a/stdlib/LinearAlgebra.version b/stdlib/LinearAlgebra.version index 3b1f7cc5847d9..88a6d52a7b804 100644 --- a/stdlib/LinearAlgebra.version +++ b/stdlib/LinearAlgebra.version @@ -1,4 +1,4 @@ LINEARALGEBRA_BRANCH = release-1.12 -LINEARALGEBRA_SHA1 = 997c4b7e7664f30645ef8bd51d8a4203e49c4631 +LINEARALGEBRA_SHA1 = dd3ea72ec654706060220118f4a65a708733b84c LINEARALGEBRA_GIT_URL := https://github.com/JuliaLang/LinearAlgebra.jl.git LINEARALGEBRA_TAR_URL = https://api.github.com/repos/JuliaLang/LinearAlgebra.jl/tarball/$1 From be84d00fcd24947a2aa9475d4477a098be4ee870 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Tue, 16 Dec 2025 21:23:28 +0100 Subject: [PATCH 08/83] bump Pkg to latest 1.12 --- .../Pkg-1dad5c51322827d29d4654b0249415e83625cf4f.tar.gz/md5 | 1 + .../Pkg-1dad5c51322827d29d4654b0249415e83625cf4f.tar.gz/sha512 | 1 + .../Pkg-53b2b5da91c27515ce129635fe184e8bd9afb09f.tar.gz/md5 | 1 - .../Pkg-53b2b5da91c27515ce129635fe184e8bd9afb09f.tar.gz/sha512 | 1 - stdlib/Pkg.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/Pkg-1dad5c51322827d29d4654b0249415e83625cf4f.tar.gz/md5 create mode 100644 deps/checksums/Pkg-1dad5c51322827d29d4654b0249415e83625cf4f.tar.gz/sha512 delete mode 100644 deps/checksums/Pkg-53b2b5da91c27515ce129635fe184e8bd9afb09f.tar.gz/md5 delete mode 100644 deps/checksums/Pkg-53b2b5da91c27515ce129635fe184e8bd9afb09f.tar.gz/sha512 diff --git a/deps/checksums/Pkg-1dad5c51322827d29d4654b0249415e83625cf4f.tar.gz/md5 b/deps/checksums/Pkg-1dad5c51322827d29d4654b0249415e83625cf4f.tar.gz/md5 new file mode 100644 index 0000000000000..c9ef7acb2b062 --- /dev/null +++ b/deps/checksums/Pkg-1dad5c51322827d29d4654b0249415e83625cf4f.tar.gz/md5 @@ -0,0 +1 @@ +54dc00afbb6c5bd7996cc351e0255be3 diff --git a/deps/checksums/Pkg-1dad5c51322827d29d4654b0249415e83625cf4f.tar.gz/sha512 b/deps/checksums/Pkg-1dad5c51322827d29d4654b0249415e83625cf4f.tar.gz/sha512 new file mode 100644 index 0000000000000..ec4cae79bd716 --- /dev/null +++ b/deps/checksums/Pkg-1dad5c51322827d29d4654b0249415e83625cf4f.tar.gz/sha512 @@ -0,0 +1 @@ +e680f3342a2fef684783890788c392897b065c158c2c3cf7e9ce0b9ab0642b3c6f93b5af5cf6671c477bb32a5ceed981f1416a4ae6bb7fb100eb1e8832591750 diff --git a/deps/checksums/Pkg-53b2b5da91c27515ce129635fe184e8bd9afb09f.tar.gz/md5 b/deps/checksums/Pkg-53b2b5da91c27515ce129635fe184e8bd9afb09f.tar.gz/md5 deleted file mode 100644 index 48b17f7ee32d2..0000000000000 --- a/deps/checksums/Pkg-53b2b5da91c27515ce129635fe184e8bd9afb09f.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -5c898e09839cfa16f80940b08bdebe9f diff --git a/deps/checksums/Pkg-53b2b5da91c27515ce129635fe184e8bd9afb09f.tar.gz/sha512 b/deps/checksums/Pkg-53b2b5da91c27515ce129635fe184e8bd9afb09f.tar.gz/sha512 deleted file mode 100644 index 7236505c4e9f1..0000000000000 --- a/deps/checksums/Pkg-53b2b5da91c27515ce129635fe184e8bd9afb09f.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -5202b09eaf172291260bc69a28944986c80a4362a9ef521b05c8ce95c69c9909439b5b2f3a52326ab820f1eff2e1ba2a8ddaa90080d9e29fd2f6e226856bda3e diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 6feeb870e2f20..48721c28ea983 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = release-1.12 -PKG_SHA1 = 53b2b5da91c27515ce129635fe184e8bd9afb09f +PKG_SHA1 = 1dad5c51322827d29d4654b0249415e83625cf4f PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 From cb92daf3b6d6c708ad96baf37f4d7fa572a034f4 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Wed, 17 Dec 2025 12:20:26 +0100 Subject: [PATCH 09/83] use a "locally frozen world age" to invoke `_artifact_str` in (#60383) (cherry picked from commit 06ebe6e5ebd8f427cd7273c0a00277ff85e4f178) --- stdlib/Artifacts/src/Artifacts.jl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/stdlib/Artifacts/src/Artifacts.jl b/stdlib/Artifacts/src/Artifacts.jl index 4af706606d326..0227d9532a49c 100644 --- a/stdlib/Artifacts/src/Artifacts.jl +++ b/stdlib/Artifacts/src/Artifacts.jl @@ -16,6 +16,13 @@ using Base.TOML: TOML export artifact_exists, artifact_path, artifact_meta, artifact_hash, select_downloadable_artifacts, find_artifacts_toml, @artifact_str +const _artifacts_world_age = Ref{UInt}(typemax(UInt)) + +function __init__() + _artifacts_world_age[] = Base.get_world_counter() + nothing +end + """ parse_toml(path::String) @@ -543,7 +550,7 @@ function jointail(dir, tail) end function _artifact_str(__module__, artifacts_toml, name, path_tail, artifact_dict, hash, platform, ::Val{LazyArtifacts}) where LazyArtifacts - world = Base._require_world_age[] + world = _artifacts_world_age[] if world == typemax(UInt) world = Base.get_world_counter() end From 496a23a563646dfecdac5100e9a3d5ccea072714 Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Tue, 4 Nov 2025 17:34:25 -0500 Subject: [PATCH 10/83] MozillaCACerts: Update to 2025-11-04 (#60041) (cherry picked from commit 589a8c68b350191f7c51326a1952a6519b158c3c) --- deps/checksums/cacert-2025-11-04.pem/md5 | 1 + deps/checksums/cacert-2025-11-04.pem/sha512 | 1 + deps/libgit2.version | 2 +- stdlib/MozillaCACerts_jll/Project.toml | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 deps/checksums/cacert-2025-11-04.pem/md5 create mode 100644 deps/checksums/cacert-2025-11-04.pem/sha512 diff --git a/deps/checksums/cacert-2025-11-04.pem/md5 b/deps/checksums/cacert-2025-11-04.pem/md5 new file mode 100644 index 0000000000000..641a98aecef02 --- /dev/null +++ b/deps/checksums/cacert-2025-11-04.pem/md5 @@ -0,0 +1 @@ +4ca8e1c3e8fc44c3ecd7a1fb9d3a6d03 diff --git a/deps/checksums/cacert-2025-11-04.pem/sha512 b/deps/checksums/cacert-2025-11-04.pem/sha512 new file mode 100644 index 0000000000000..bbd48b9475d7f --- /dev/null +++ b/deps/checksums/cacert-2025-11-04.pem/sha512 @@ -0,0 +1 @@ +9d9f7ecc829bafc222501d8a66852d96a51f522b04a82963e4166c87b85d6a5e5eedb50ced2ef3026cd7cb06fcb4b7dca59c4157813a067cb7b185e32f2957ec diff --git a/deps/libgit2.version b/deps/libgit2.version index ffba640e3b24e..5a7fb591098bb 100644 --- a/deps/libgit2.version +++ b/deps/libgit2.version @@ -11,4 +11,4 @@ LIBGIT2_SHA1=338e6fb681369ff0537719095e22ce9dc602dbf0 # The versions of cacert.pem are identified by the date (YYYY-MM-DD) of their changes. # See https://curl.haxx.se/docs/caextract.html for more details. # Keep in sync with `stdlib/MozillaCACerts_jll/Project.toml`. -MOZILLA_CACERT_VERSION := 2025-05-20 +MOZILLA_CACERT_VERSION := 2025-11-04 diff --git a/stdlib/MozillaCACerts_jll/Project.toml b/stdlib/MozillaCACerts_jll/Project.toml index 57c5526a6f1f2..d63251d59d58f 100644 --- a/stdlib/MozillaCACerts_jll/Project.toml +++ b/stdlib/MozillaCACerts_jll/Project.toml @@ -1,7 +1,7 @@ name = "MozillaCACerts_jll" uuid = "14a3606d-f60d-562e-9121-12d972cd8159" # Keep in sync with `deps/libgit2.version`. -version = "2025.05.20" +version = "2025.11.04" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" From 8086974f0601e08cdd59d1909f312a68e6f810dc Mon Sep 17 00:00:00 2001 From: Em Chu <61633163+mlechu@users.noreply.github.com> Date: Fri, 21 Nov 2025 20:18:32 -0800 Subject: [PATCH 11/83] Fix `remove-argument-side-effects` with keyword call (#60195) Fix #60152, which impacted both lowering implementations. `remove-argument-side-effects` assumed all `kw` arguments from a `parameters` block had already been dumped into the argument list, which is not true in some cases. In addition: - JuliaLowering hit a MethodError in the dumped-`kw` case regardless. There are other issues with `kw` which I'm ignoring in this PR (see https://github.com/JuliaLang/julia/pull/60162) - Delete some ancient history: `&` [used to be a valid argument](https://github.com/JuliaLang/julia/commit/a378b750fd7e387f0504e7605c464944092e29e1#diff-5d79463faae0f7f19454c7f9888498d9f876082e258ab3efdca36a0ee64b0c87L72) head sometime in 2012 apparently! (cherry picked from commit 2be8847086ae4b44feb011204a93984294870156) --- src/julia-syntax.scm | 10 ++++++---- test/syntax.jl | 11 ++++++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index aad8105b34308..07668878a20e1 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1790,11 +1790,13 @@ (cons e '()) (let ((a '())) (define (arg-to-temp x) - (cond ((effect-free? x) x) - ((or (eq? (car x) '...) (eq? (car x) '&)) - `(,(car x) ,(arg-to-temp (cadr x)))) + (cond ((effect-free? x) x) + ((eq? (car x) '...) + `(... ,(arg-to-temp (cadr x)))) ((eq? (car x) 'kw) - `(,(car x) ,(cadr x) ,(arg-to-temp (caddr x)))) + `(kw ,(cadr x) ,(arg-to-temp (caddr x)))) + ((eq? (car x) 'parameters) + `(parameters ,@(map arg-to-temp (cdr x)))) (else (let ((g (make-ssavalue))) (begin (set! a (cons `(= ,g ,x) a)) diff --git a/test/syntax.jl b/test/syntax.jl index 70640e6c93d67..b2d7ebfa96f98 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -3659,7 +3659,7 @@ end @test p("public() = 6") == Expr(:(=), Expr(:call, :public), Expr(:block, 6)) end -@testset "removing argument sideeffects" begin +@testset "removing argument side effects" begin # Allow let blocks in broadcasted LHSes, but only evaluate them once: execs = 0 array = [1] @@ -3675,6 +3675,15 @@ end let; execs += 1; array; end::Vector{Int} .= 7 @test array == [7] @test execs == 4 + + # remove argument side effects on lhs kwcall + pa_execs = 0 + kw_execs = 0 + f60152(v, pa; kw) = copy(v) + @test (f60152([1, 2, 3], 0; kw=0) .*= 2) == [2,4,6] + @test (f60152([1, 2, 3], (pa_execs+=1); kw=(kw_execs+=1)) .*= 2) == [2,4,6] + @test pa_execs === 1 + @test kw_execs === 1 end # Allow GlobalRefs in macro definition From dda778899123e1e20a138783f962c8ebaba2a43a Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Wed, 3 Dec 2025 13:49:53 -0500 Subject: [PATCH 12/83] Make stdlib precompile failures throw (#60308) (cherry picked from commit 44ecbcf92df9658751d1d6b94f48f33375ef2b17) --- pkgimage.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgimage.mk b/pkgimage.mk index 78b2618be549f..e90e0e9618808 100644 --- a/pkgimage.mk +++ b/pkgimage.mk @@ -26,7 +26,7 @@ print-depot-path: $(BUILDDIR)/stdlib/%.image: $(JULIAHOME)/stdlib/Project.toml $(JULIAHOME)/stdlib/Manifest.toml $(INDEPENDENT_STDLIBS_SRCS) $(JULIA_DEPOT_PATH)/compiled @$(call PRINT_JULIA, JULIA_CPU_TARGET="$(JULIA_CPU_TARGET)" $(call spawn,$(JULIA_EXECUTABLE)) --startup-file=no -e \ - 'Base.Precompilation.precompilepkgs(configs=[``=>Base.CacheFlags(debug_level=2, opt_level=3), ``=>Base.CacheFlags(check_bounds=1, debug_level=2, opt_level=3)])') + 'Base.Precompilation.precompilepkgs(configs=[``=>Base.CacheFlags(debug_level=2, opt_level=3), ``=>Base.CacheFlags(check_bounds=1, debug_level=2, opt_level=3)]; strict=true)') touch $@ $(BUILDDIR)/stdlib/release.image: $(build_private_libdir)/sys.$(SHLIB_EXT) From 32ebc18afeec0fcb3d50cc5b9ca2df7231730281 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 18 Dec 2025 17:29:31 +0100 Subject: [PATCH 13/83] Fix world age docs link, point to correct manual version (manual backport to 1.12) (#60385) Manual backport of #60384 to `release-1.12` (there is currently no `backports-release-1.12` branch; once there is, this PR could of course be re-targeted to that). --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index f5f68e508bdd9..17dd8ced3d56c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,7 +8,7 @@ New language features entry points. Entry points can be marked using `Base.Experimental.entrypoint` ([#55047]). Not all code is expected to work with this option, and since it is experimental you may encounter problems. * Redefinition of constants is now well defined and follows world age semantics ([#57253]). Additional redefinitions - (e.g. of types) are now allowed. See [the new manual chapter on world age](https://docs.julialang.org/en/v1.13-dev/manual/worldage/). + (e.g. of types) are now allowed. See [the new manual chapter on world age](https://docs.julialang.org/en/v1/manual/worldage/). * A new keyword argument `usings::Bool` has been added to `names`, returning all names visible via `using` ([#54609]). * The `@atomic` macro family now supports reference assignment syntax, e.g. `@atomic :monotonic v[3] += 4`, From 4c54cafbd6db26108b3432b7c1906aaa0ff46e31 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Fri, 19 Dec 2025 17:22:39 +0900 Subject: [PATCH 14/83] compiler: Fix typo in `abstract_invoke` (#60414) Fixed `method_ir_ci` typo in the `abstract_invoke`. --- Compiler/src/abstractinterpretation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Compiler/src/abstractinterpretation.jl b/Compiler/src/abstractinterpretation.jl index b455f078d83eb..f27a68da44b90 100644 --- a/Compiler/src/abstractinterpretation.jl +++ b/Compiler/src/abstractinterpretation.jl @@ -2247,7 +2247,7 @@ function abstract_invoke(interp::AbstractInterpreter, arginfo::ArgInfo, si::Stmt return Future(CallMeta(Bottom, ErrorException, EFFECTS_THROWS, NoCallInfo())) end # TODO: When we add curing, we may want to assume this is nothrow - if (method_or_ci.owner === Nothing && method_ir_ci.def.def isa Method) + if (method_or_ci.owner === Nothing && method_or_ci.def.def isa Method) exct = Union{exct, ErrorException} end update_valid_age!(sv, callee_valid_range) From 483d527221c0d2770003cf586f4f2bf47a2299cd Mon Sep 17 00:00:00 2001 From: dkarrasch <26658441+dkarrasch@users.noreply.github.com> Date: Fri, 19 Dec 2025 14:38:49 +0000 Subject: [PATCH 15/83] =?UTF-8?q?=F0=9F=A4=96=20[release-1.12]=20Bump=20Li?= =?UTF-8?q?nearAlgebra=20stdlib=20dd3ea72=20=E2=86=92=207249e66?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../md5 | 1 + .../sha512 | 1 + .../md5 | 1 - .../sha512 | 1 - stdlib/LinearAlgebra.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/LinearAlgebra-7249e662d66b53da6c9335ea748eac2750c2924f.tar.gz/md5 create mode 100644 deps/checksums/LinearAlgebra-7249e662d66b53da6c9335ea748eac2750c2924f.tar.gz/sha512 delete mode 100644 deps/checksums/LinearAlgebra-dd3ea72ec654706060220118f4a65a708733b84c.tar.gz/md5 delete mode 100644 deps/checksums/LinearAlgebra-dd3ea72ec654706060220118f4a65a708733b84c.tar.gz/sha512 diff --git a/deps/checksums/LinearAlgebra-7249e662d66b53da6c9335ea748eac2750c2924f.tar.gz/md5 b/deps/checksums/LinearAlgebra-7249e662d66b53da6c9335ea748eac2750c2924f.tar.gz/md5 new file mode 100644 index 0000000000000..cbd119f9a07e5 --- /dev/null +++ b/deps/checksums/LinearAlgebra-7249e662d66b53da6c9335ea748eac2750c2924f.tar.gz/md5 @@ -0,0 +1 @@ +c8fea09ab0a67dcd9bacc413a008056b diff --git a/deps/checksums/LinearAlgebra-7249e662d66b53da6c9335ea748eac2750c2924f.tar.gz/sha512 b/deps/checksums/LinearAlgebra-7249e662d66b53da6c9335ea748eac2750c2924f.tar.gz/sha512 new file mode 100644 index 0000000000000..01c026a488114 --- /dev/null +++ b/deps/checksums/LinearAlgebra-7249e662d66b53da6c9335ea748eac2750c2924f.tar.gz/sha512 @@ -0,0 +1 @@ +f44e5518d45d568a56116fcef058c006adefff6752b7bfecd29afffa7fc797739271bde2d3a6d0813d89973c862341d5ee47347a933146a43108ea716b133672 diff --git a/deps/checksums/LinearAlgebra-dd3ea72ec654706060220118f4a65a708733b84c.tar.gz/md5 b/deps/checksums/LinearAlgebra-dd3ea72ec654706060220118f4a65a708733b84c.tar.gz/md5 deleted file mode 100644 index b49795485f679..0000000000000 --- a/deps/checksums/LinearAlgebra-dd3ea72ec654706060220118f4a65a708733b84c.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -89bf516f59c6e35cb0ca090d93fa347b diff --git a/deps/checksums/LinearAlgebra-dd3ea72ec654706060220118f4a65a708733b84c.tar.gz/sha512 b/deps/checksums/LinearAlgebra-dd3ea72ec654706060220118f4a65a708733b84c.tar.gz/sha512 deleted file mode 100644 index 3c87627b5a126..0000000000000 --- a/deps/checksums/LinearAlgebra-dd3ea72ec654706060220118f4a65a708733b84c.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -286da5f2e9d6472f52e9eeee4ee9ec7b09bea8584fe95764de459b923c2323cb6ed6d9f04748c12c7f521a0a5bca07ec6ea69668e2f8e2a52595ce6a16f62410 diff --git a/stdlib/LinearAlgebra.version b/stdlib/LinearAlgebra.version index 88a6d52a7b804..6caafbaf313ac 100644 --- a/stdlib/LinearAlgebra.version +++ b/stdlib/LinearAlgebra.version @@ -1,4 +1,4 @@ LINEARALGEBRA_BRANCH = release-1.12 -LINEARALGEBRA_SHA1 = dd3ea72ec654706060220118f4a65a708733b84c +LINEARALGEBRA_SHA1 = 7249e662d66b53da6c9335ea748eac2750c2924f LINEARALGEBRA_GIT_URL := https://github.com/JuliaLang/LinearAlgebra.jl.git LINEARALGEBRA_TAR_URL = https://api.github.com/repos/JuliaLang/LinearAlgebra.jl/tarball/$1 From 3b59c5a7e395437947d8d591cd2b73edc0acdc41 Mon Sep 17 00:00:00 2001 From: IanButterworth <1694067+IanButterworth@users.noreply.github.com> Date: Sat, 20 Dec 2025 15:49:53 +0000 Subject: [PATCH 16/83] =?UTF-8?q?=F0=9F=A4=96=20[release-1.12]=20Bump=20Pk?= =?UTF-8?q?g=20stdlib=201dad5c513=20=E2=86=92=20b322a8ff7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Pkg-1dad5c51322827d29d4654b0249415e83625cf4f.tar.gz/md5 | 1 - .../Pkg-1dad5c51322827d29d4654b0249415e83625cf4f.tar.gz/sha512 | 1 - .../Pkg-b322a8ff786472d680a972e57575b4586fefe018.tar.gz/md5 | 1 + .../Pkg-b322a8ff786472d680a972e57575b4586fefe018.tar.gz/sha512 | 1 + stdlib/Pkg.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/Pkg-1dad5c51322827d29d4654b0249415e83625cf4f.tar.gz/md5 delete mode 100644 deps/checksums/Pkg-1dad5c51322827d29d4654b0249415e83625cf4f.tar.gz/sha512 create mode 100644 deps/checksums/Pkg-b322a8ff786472d680a972e57575b4586fefe018.tar.gz/md5 create mode 100644 deps/checksums/Pkg-b322a8ff786472d680a972e57575b4586fefe018.tar.gz/sha512 diff --git a/deps/checksums/Pkg-1dad5c51322827d29d4654b0249415e83625cf4f.tar.gz/md5 b/deps/checksums/Pkg-1dad5c51322827d29d4654b0249415e83625cf4f.tar.gz/md5 deleted file mode 100644 index c9ef7acb2b062..0000000000000 --- a/deps/checksums/Pkg-1dad5c51322827d29d4654b0249415e83625cf4f.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -54dc00afbb6c5bd7996cc351e0255be3 diff --git a/deps/checksums/Pkg-1dad5c51322827d29d4654b0249415e83625cf4f.tar.gz/sha512 b/deps/checksums/Pkg-1dad5c51322827d29d4654b0249415e83625cf4f.tar.gz/sha512 deleted file mode 100644 index ec4cae79bd716..0000000000000 --- a/deps/checksums/Pkg-1dad5c51322827d29d4654b0249415e83625cf4f.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -e680f3342a2fef684783890788c392897b065c158c2c3cf7e9ce0b9ab0642b3c6f93b5af5cf6671c477bb32a5ceed981f1416a4ae6bb7fb100eb1e8832591750 diff --git a/deps/checksums/Pkg-b322a8ff786472d680a972e57575b4586fefe018.tar.gz/md5 b/deps/checksums/Pkg-b322a8ff786472d680a972e57575b4586fefe018.tar.gz/md5 new file mode 100644 index 0000000000000..fbc81b025a8f9 --- /dev/null +++ b/deps/checksums/Pkg-b322a8ff786472d680a972e57575b4586fefe018.tar.gz/md5 @@ -0,0 +1 @@ +9fbd2f2f522bf0b5fd0d6b40f722db49 diff --git a/deps/checksums/Pkg-b322a8ff786472d680a972e57575b4586fefe018.tar.gz/sha512 b/deps/checksums/Pkg-b322a8ff786472d680a972e57575b4586fefe018.tar.gz/sha512 new file mode 100644 index 0000000000000..576ad3c62915e --- /dev/null +++ b/deps/checksums/Pkg-b322a8ff786472d680a972e57575b4586fefe018.tar.gz/sha512 @@ -0,0 +1 @@ +77e2f3729e58b74cfdd1fc2d991fc6552e7f7ceb7b9fdc837e5885932e2f15d6ab3c76b6ab90b1a6c66050dab7279abc0b976ee52b840b757dd13b1a955f5c5c diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 48721c28ea983..853940e299a8e 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = release-1.12 -PKG_SHA1 = 1dad5c51322827d29d4654b0249415e83625cf4f +PKG_SHA1 = b322a8ff786472d680a972e57575b4586fefe018 PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 From c7d674ab0cf65f04da95774df8b150cd13336070 Mon Sep 17 00:00:00 2001 From: Sam Schweigel Date: Sat, 6 Dec 2025 05:59:43 -0800 Subject: [PATCH 17/83] Don't create a subprocess in the REPL precompile script (#60326) (cherry picked from commit 18aa2377728fb6c4f5b2b388f76690c1d3f8e3cb) --- stdlib/REPL/src/precompile.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/REPL/src/precompile.jl b/stdlib/REPL/src/precompile.jl index a4d289db8cd40..21ca166b94a71 100644 --- a/stdlib/REPL/src/precompile.jl +++ b/stdlib/REPL/src/precompile.jl @@ -61,7 +61,7 @@ function repl_workload() display("a string") foo(x) = 1 @time @eval foo(1) - ; pwd + ; $CTRL_C $CTRL_R$CTRL_C# ? reinterpret From 4539b7b4af8c89dadc72bd079965bd1583bb84b4 Mon Sep 17 00:00:00 2001 From: Nathan Zimmerberg <39104088+nhz2@users.noreply.github.com> Date: Mon, 22 Dec 2025 09:26:30 -0500 Subject: [PATCH 18/83] [backports-release-1.12] Fix 7z rpath (#60419) fix #60220 --- Make.inc | 2 +- Makefile | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Make.inc b/Make.inc index c2ccf6757e3c9..a145980e0264c 100644 --- a/Make.inc +++ b/Make.inc @@ -381,7 +381,7 @@ $(foreach D,build_libdir build_private_libdir,$(eval $(call cache_rel_path,$(D), # Save a special one: reverse_private_libdir_rel: usually just `../`, but good to be general: reverse_private_libdir_rel_eval = $(call rel_path,$(private_libdir),$(libdir)) reverse_private_libdir_rel = $(call hit_cache,reverse_private_libdir_rel_eval) -reverse_private_libexecdir_rel_eval = $(call rel_path,$(private_libexecdir),$(libdir)) +reverse_private_libexecdir_rel_eval = $(call rel_path,$(private_libexecdir),$(private_libdir)) reverse_private_libexecdir_rel = $(call hit_cache,reverse_private_libexecdir_rel_eval) reverse_build_private_libexecdir_rel_eval = $(call rel_path,$(build_private_libexecdir),$(build_libdir)) reverse_build_private_libexecdir_rel = $(call hit_cache,reverse_build_private_libexecdir_rel_eval) diff --git a/Makefile b/Makefile index bae449b255a10..259113e430c41 100644 --- a/Makefile +++ b/Makefile @@ -485,6 +485,37 @@ else ifeq ($(JULIA_BUILD_MODE),debug) $(PATCHELF) $(PATCHELF_SET_RPATH_ARG) '$$ORIGIN:$$ORIGIN/$(reverse_private_libdir_rel)' $(DESTDIR)$(private_libdir)/libjulia-internal-debug.$(SHLIB_EXT) $(PATCHELF) $(PATCHELF_SET_RPATH_ARG) '$$ORIGIN:$$ORIGIN/$(reverse_private_libdir_rel)' $(DESTDIR)$(private_libdir)/libjulia-codegen-debug.$(SHLIB_EXT) endif +endif + +ifeq ($(OS), Darwin) +ifneq ($(DARWIN_FRAMEWORK),1) + for j in $(JL_PRIVATE_TOOLS) ; do \ + [ -L $(DESTDIR)$(private_libexecdir)/$$j ] && continue; \ + install_name_tool -rpath @loader_path/$(build_libdir_rel) @executable_path/$(reverse_private_libexecdir_rel) $(DESTDIR)$(private_libexecdir)/$$j || exit 1; \ + done +endif +else ifneq (,$(findstring $(OS),Linux FreeBSD)) + for j in $(JL_PRIVATE_TOOLS) ; do \ + [ -L $(DESTDIR)$(private_libexecdir)/$$j ] && continue; \ + $(PATCHELF) $(PATCHELF_SET_RPATH_ARG) '$$ORIGIN/$(reverse_private_libexecdir_rel)' $(DESTDIR)$(private_libexecdir)/$$j || exit 1; \ + done +endif + +ifneq ($(reverse_private_libexecdir_rel),$(reverse_build_private_libexecdir_rel)) +ifeq ($(OS), Darwin) +ifneq ($(DARWIN_FRAMEWORK),1) + for j in $(JL_PRIVATE_EXES) ; do \ + [ $$j = 7z ] && continue; \ + [ -L $(DESTDIR)$(private_libexecdir)/$$j ] && continue; \ + install_name_tool -rpath @executable_path/$(reverse_build_private_libexecdir_rel) @executable_path/$(reverse_private_libexecdir_rel) $(DESTDIR)$(private_libexecdir)/$$j || exit 1; \ + done +endif +else ifneq (,$(findstring $(OS),Linux FreeBSD)) + for j in $(JL_PRIVATE_EXES) ; do \ + [ -L $(DESTDIR)$(private_libexecdir)/$$j ] && continue; \ + $(PATCHELF) $(PATCHELF_SET_RPATH_ARG) '$$ORIGIN/$(reverse_private_libexecdir_rel)' $(DESTDIR)$(private_libexecdir)/$$j || exit 1; \ + done +endif endif # Fix rpaths for dependencies. This should be fixed in BinaryBuilder later. From f6eba2bb25485b57773e5b515d5ad8f209f6ef6e Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 23 Dec 2025 06:43:54 +0100 Subject: [PATCH 19/83] Fix JET warning in `_spawn_primitive` (#60452) In various packages I am JETing, I see the same error being reported: > local variable `pp` may be undefined: pp::Base.Process This patch helps JET proof that there is no actual problem. Would be kinda nice to see this backported to 1.12 so that if I run JET with 1.12.4 this is not reported anymore. And of course also to 1.13. --- base/process.jl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/base/process.jl b/base/process.jl index fbc4acfd83e80..1a2324cb5d86e 100644 --- a/base/process.jl +++ b/base/process.jl @@ -131,15 +131,14 @@ end if err == 0 pp = Process(cmd, handle, syncd) associate_julia_struct(handle, pp) + iolock_end() + return pp else ccall(:jl_forceclose_uv, Cvoid, (Ptr{Cvoid},), handle) # will call free on handle eventually + iolock_end() + throw(_UVError("could not spawn " * repr(cmd), err)) end - iolock_end() end - if err != 0 - throw(_UVError("could not spawn " * repr(cmd), err)) - end - return pp end _spawn(cmds::AbstractCmd) = _spawn(cmds, SpawnIOs()) From 46c22c854671989c53dfc07534c1a269cc775b30 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 23 Dec 2025 06:50:42 +0100 Subject: [PATCH 20/83] Fix JET warnings in `copy_chunks!`, `copy_chunks_rtol!`, `fill_chunks!` (#60453) > local variable `msk_d1` may be undefined: msk_d1::UInt64 The code logic was actually right, but by transforming the code, JET can also see it (and arguably it is now also easier for a human to see that everything is correct) --- base/bitarray.jl | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/base/bitarray.jl b/base/bitarray.jl index 93fa48c56e379..2b73b1ea8a710 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -151,16 +151,14 @@ function copy_chunks!(dest::Vector{UInt64}, pos_d::Int, src::Vector{UInt64}, pos delta_ks = ks1 - ks0 u = _msk64 + msk_d0 = ~(u << ld0) + msk_d1 = (u << (ld1+1)) if delta_kd == 0 - msk_d0 = ~(u << ld0) | (u << (ld1+1)) - else - msk_d0 = ~(u << ld0) - msk_d1 = (u << (ld1+1)) + msk_d0 |= msk_d1 end + msk_s0 = (u << ls0) if delta_ks == 0 - msk_s0 = (u << ls0) & ~(u << (ls1+1)) - else - msk_s0 = (u << ls0) + msk_s0 &= ~(u << (ls1+1)) end chunk_s0 = glue_src_bitchunks(src, ks0, ks1, msk_s0, ls0) @@ -211,16 +209,14 @@ function copy_chunks_rtol!(chunks::Vector{UInt64}, pos_d::Int, pos_s::Int, numbi delta_kd = kd1 - kd0 delta_ks = ks1 - ks0 + msk_d0 = ~(u << ld0) + msk_d1 = (u << (ld1+1)) if delta_kd == 0 - msk_d0 = ~(u << ld0) | (u << (ld1+1)) - else - msk_d0 = ~(u << ld0) - msk_d1 = (u << (ld1+1)) + msk_d0 |= msk_d1 end + msk_s0 = (u << ls0) if delta_ks == 0 - msk_s0 = (u << ls0) & ~(u << (ls1+1)) - else - msk_s0 = (u << ls0) + msk_s0 &= ~(u << (ls1+1)) end chunk_s0 = glue_src_bitchunks(chunks, ks0, ks1, msk_s0, ls0) & ~(u << s) @@ -246,11 +242,10 @@ function fill_chunks!(Bc::Array{UInt64}, x::Bool, pos::Int, numbits::Int) k1, l1 = get_chunks_id(pos+numbits-1) u = _msk64 + msk0 = (u << l0) + msk1 = ~(u << (l1+1)) if k1 == k0 - msk0 = (u << l0) & ~(u << (l1+1)) - else - msk0 = (u << l0) - msk1 = ~(u << (l1+1)) + msk0 &= msk1 end @inbounds if x Bc[k0] |= msk0 From ae7a1c64f5a029d01eacb3caf3903af115daa956 Mon Sep 17 00:00:00 2001 From: dkarrasch <26658441+dkarrasch@users.noreply.github.com> Date: Tue, 23 Dec 2025 16:46:52 +0000 Subject: [PATCH 21/83] =?UTF-8?q?=F0=9F=A4=96=20[release-1.12]=20Bump=20Sp?= =?UTF-8?q?arseArrays=20stdlib=205d674dc=20=E2=86=92=20f81a30d?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../md5 | 1 - .../sha512 | 1 - .../md5 | 1 + .../sha512 | 1 + stdlib/SparseArrays.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/SparseArrays-5d674dc7bd90156cf8ecea4e143b69b5a5b7640d.tar.gz/md5 delete mode 100644 deps/checksums/SparseArrays-5d674dc7bd90156cf8ecea4e143b69b5a5b7640d.tar.gz/sha512 create mode 100644 deps/checksums/SparseArrays-f81a30d962b03d4048b26439d60979673e343b67.tar.gz/md5 create mode 100644 deps/checksums/SparseArrays-f81a30d962b03d4048b26439d60979673e343b67.tar.gz/sha512 diff --git a/deps/checksums/SparseArrays-5d674dc7bd90156cf8ecea4e143b69b5a5b7640d.tar.gz/md5 b/deps/checksums/SparseArrays-5d674dc7bd90156cf8ecea4e143b69b5a5b7640d.tar.gz/md5 deleted file mode 100644 index ab3e4ebfe9f25..0000000000000 --- a/deps/checksums/SparseArrays-5d674dc7bd90156cf8ecea4e143b69b5a5b7640d.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -eadaa92895c8d4d33eb601165ef765d5 diff --git a/deps/checksums/SparseArrays-5d674dc7bd90156cf8ecea4e143b69b5a5b7640d.tar.gz/sha512 b/deps/checksums/SparseArrays-5d674dc7bd90156cf8ecea4e143b69b5a5b7640d.tar.gz/sha512 deleted file mode 100644 index 7a250e67b00d3..0000000000000 --- a/deps/checksums/SparseArrays-5d674dc7bd90156cf8ecea4e143b69b5a5b7640d.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -bb37377b360eca1a32c78b1d11b83c7e918a8ddb9df79388694b6f415dc5d5cf6182df7437869b3970011e5dcda4a3f821b58498bfa6fd7df697fcd51383ca12 diff --git a/deps/checksums/SparseArrays-f81a30d962b03d4048b26439d60979673e343b67.tar.gz/md5 b/deps/checksums/SparseArrays-f81a30d962b03d4048b26439d60979673e343b67.tar.gz/md5 new file mode 100644 index 0000000000000..372c4735d1c07 --- /dev/null +++ b/deps/checksums/SparseArrays-f81a30d962b03d4048b26439d60979673e343b67.tar.gz/md5 @@ -0,0 +1 @@ +230a4d9544d2cec7c4adf9a50d228345 diff --git a/deps/checksums/SparseArrays-f81a30d962b03d4048b26439d60979673e343b67.tar.gz/sha512 b/deps/checksums/SparseArrays-f81a30d962b03d4048b26439d60979673e343b67.tar.gz/sha512 new file mode 100644 index 0000000000000..6f1838c5bb750 --- /dev/null +++ b/deps/checksums/SparseArrays-f81a30d962b03d4048b26439d60979673e343b67.tar.gz/sha512 @@ -0,0 +1 @@ +d66a3b6e032af45b78f71d8c5851c3e6fe1c5159f4c4428b64f1f6a52a111a488a9cec8f702a9e5de96593f5d4735f7490ae6c33eee7155b31f743b82aebd38b diff --git a/stdlib/SparseArrays.version b/stdlib/SparseArrays.version index b6d9a820d9a06..98763ae71e777 100644 --- a/stdlib/SparseArrays.version +++ b/stdlib/SparseArrays.version @@ -1,4 +1,4 @@ SPARSEARRAYS_BRANCH = release-1.12 -SPARSEARRAYS_SHA1 = 5d674dc7bd90156cf8ecea4e143b69b5a5b7640d +SPARSEARRAYS_SHA1 = f81a30d962b03d4048b26439d60979673e343b67 SPARSEARRAYS_GIT_URL := https://github.com/JuliaSparse/SparseArrays.jl.git SPARSEARRAYS_TAR_URL = https://api.github.com/repos/JuliaSparse/SparseArrays.jl/tarball/$1 From d15e1fb951d0a9687b6e9fcfff2d53ee8481a0f9 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 24 Dec 2025 08:23:46 +0100 Subject: [PATCH 22/83] Fix JET warning in `TOML.parse_array` (#60465) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As a bonus, also change `T == BigInt` to `T === BigInt`. Fixes this: ``` │┌ load_artifacts_toml(artifacts_toml::String) @ Artifacts /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-honeycrisp-R17H3W25T9.0/build/default-honeycrisp-R17H3W25T9-0/julialang/julia-release-1-dot-12/usr/share/julia/stdlib/v1.12/Artifacts/src/Artifacts.jl:315 ││┌ load_artifacts_toml(artifacts_toml::String; pkg_uuid::Nothing) @ Artifacts /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-honeycrisp-R17H3W25T9.0/build/default-honeycrisp-R17H3W25T9-0/julialang/julia-release-1-dot-12/usr/share/julia/stdlib/v1.12/Artifacts/src/Artifacts.jl:317 │││┌ parse_toml(path::String) @ Artifacts /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-honeycrisp-R17H3W25T9.0/build/default-honeycrisp-R17H3W25T9-0/julialang/julia-release-1-dot-12/usr/share/julia/stdlib/v1.12/Artifacts/src/Artifacts.jl:26 ││││┌ parsed_toml(project_file::String) @ Base ./loading.jl:276 │││││┌ parsed_toml(project_file::String, toml_cache::Base.TOMLCache{nothing}, toml_lock::ReentrantLock) @ Base ./loading.jl:278 ││││││┌ lock(f::Base.var"#parsed_toml##0#parsed_toml##1"{String, Base.TOMLCache{nothing}}, l::ReentrantLock) @ Base ./lock.jl:335 │││││││┌ (::Base.var"#parsed_toml##0#parsed_toml##1"{String, Base.TOMLCache{nothing}})() @ Base ./loading.jl:281 ││││││││┌ Base.CachedTOMLDict(p::Base.TOML.Parser{nothing}, path::String) @ Base ./loading.jl:222 │││││││││┌ parse(l::Base.TOML.Parser{nothing}) @ Base.TOML ./toml_parser.jl:444 ││││││││││┌ tryparse(l::Base.TOML.Parser{nothing}) @ Base.TOML ./toml_parser.jl:453 │││││││││││┌ parse_toplevel(l::Base.TOML.Parser{nothing}) @ Base.TOML ./toml_parser.jl:157 ││││││││││││┌ parse_array(l::Base.TOML.Parser{nothing}) @ Base.TOML ./toml_parser.jl:719 │││││││││││││┌ getproperty(x::Nothing, f::Symbol) @ Base ./Base_compiler.jl:54 ││││││││││││││ invalid builtin function call: getfield(x::Nothing, f::Symbol) │││││││││││││└──────────────────── ``` --- base/toml_parser.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/toml_parser.jl b/base/toml_parser.jl index 378322e8cba95..46208eeff4195 100644 --- a/base/toml_parser.jl +++ b/base/toml_parser.jl @@ -716,8 +716,8 @@ function parse_array(l::Parser{Dates})::Err{Vector} where Dates copyto_typed!(new, array) elseif T === Union{} new = Any[] - elseif (T === TOMLDict) || (T == BigInt) || (T === UInt128) || (T === Int128) || (T <: Vector) || - (T === Dates.Date) || (T === Dates.Time) || (T === Dates.DateTime) + elseif (T === TOMLDict) || (T === BigInt) || (T === UInt128) || (T === Int128) || (T <: Vector) || + (Dates !== nothing && ((T === Dates.Date) || (T === Dates.Time) || (T === Dates.DateTime))) # do nothing, leave as Vector{Any} new = array else @assert false end From fb87ed4893a3b00f1fc8b5db4b0485b6e80575ff Mon Sep 17 00:00:00 2001 From: Max Horn Date: Wed, 24 Dec 2025 08:24:47 +0100 Subject: [PATCH 23/83] Fix JET warning in Base.sendfile (#60466) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Help JET (and humans?) understand that src_file and dst_file won't be used without being defined. Fixes this JET report: ``` │┌ cp(src::AbstractString, dst::String) @ Base.Filesystem ./file.jl:404 ││┌ cp(src::AbstractString, dst::String; force::Bool, follow_symlinks::Bool) @ Base.Filesystem ./file.jl:410 │││┌ kwcall(::@NamedTuple{force::Bool, follow_symlinks::Bool}, ::typeof(Base.Filesystem.cptree), src::String, dst::String) @ Base.Filesystem ./file.jl:366 ││││┌ cptree(src::String, dst::String; force::Bool, follow_symlinks::Bool) @ Base.Filesystem ./file.jl:379 │││││┌ sendfile(src::String, dst::String) @ Base.Filesystem ./file.jl:1282 ││││││ local variable `src_file` may be undefined: src_file::Base.Filesystem.File │││││└──────────────────── │││││┌ sendfile(src::String, dst::String) @ Base.Filesystem ./file.jl:1283 ││││││ local variable `src_file` may be undefined: src_file::Base.Filesystem.File │││││└──────────────────── │││││┌ sendfile(src::String, dst::String) @ Base.Filesystem ./file.jl:1285 ││││││ local variable `dst_file` may be undefined: dst_file::Base.Filesystem.File │││││└──────────────────── │││││┌ sendfile(src::String, dst::String) @ Base.Filesystem ./file.jl:1286 ││││││ local variable `dst_file` may be undefined: dst_file::Base.Filesystem.File │││││└──────────────────── ``` --- base/file.jl | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/base/file.jl b/base/file.jl index ce9bc76256fd3..7c2d8ebe86de8 100644 --- a/base/file.jl +++ b/base/file.jl @@ -1267,22 +1267,19 @@ function rename(oldpath::AbstractString, newpath::AbstractString) end function sendfile(src::AbstractString, dst::AbstractString) - src_open = false - dst_open = false - local src_file, dst_file + src_file = nothing + dst_file = nothing try src_file = open(src, JL_O_RDONLY) - src_open = true dst_file = open(dst, JL_O_CREAT | JL_O_TRUNC | JL_O_WRONLY, filemode(src_file)) - dst_open = true bytes = filesize(stat(src_file)) sendfile(dst_file, src_file, Int64(0), Int(bytes)) finally - if src_open && isopen(src_file) + if src_file !== nothing && isopen(src_file) close(src_file) end - if dst_open && isopen(dst_file) + if dst_file !== nothing && isopen(dst_file) close(dst_file) end end From 798e447360eefe0522fd7550e8722c64de707fc6 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 27 Dec 2025 10:34:59 +0100 Subject: [PATCH 24/83] Fix JET warning related to `_array_for` (#60461) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calls to this method are produced by syntax lowering for simple typed comprehensions. The current signature is ambiguous, making JET believe that the modified method could have ended up invoking itself. Resolve this by renaming the other methods. These are the the warnings I am seeing while JETing a package: ``` ││┌ _array_for(::Type{T}, itr::AbstractVector{T} where T<:NCRingElement, isz::Any) where T @ Base ./array.jl:673 │││┌ _array_for(::Type, itr::Base.SizeUnknown, isz::Any) @ Base ./array.jl:673 ││││┌ _similar_shape(itr::Base.SizeUnknown, ::Base.HasLength) @ Base ./array.jl:657 │││││ no matching method found `length(::Base.SizeUnknown)`: length(itr::Base.SizeUnknown) ││││└──────────────────── ││││┌ _similar_shape(itr::Base.SizeUnknown, ::Base.HasShape) @ Base ./array.jl:658 │││││┌ axes(A::Base.SizeUnknown) @ Base ./abstractarray.jl:98 ││││││ no matching method found `size(::Base.SizeUnknown)`: size(A::Base.SizeUnknown) │││││└──────────────────── ``` and ``` ││││││││┌ Base.AnnotatedString(s::String, annots::Any) @ Base ./strings/annotated.jl:107 │││││││││┌ collect(::Type{@NamedTuple{region::UnitRange{Int64}, label::Symbol, value}}, itr::Any) @ Base ./array.jl:641 ││││││││││┌ _collect(::Type{@NamedTuple{…}}, itr::Any, isz::Union{Base.HasLength, Base.HasShape}) @ Base ./array.jl:643 │││││││││││┌ _array_for(::Type{@NamedTuple{region::UnitRange{Int64}, label::Symbol, value}}, itr::Base.HasLength, isz::Any) @ Base ./array.jl:673 ││││││││││││┌ _similar_shape(itr::Base.HasLength, ::Base.HasLength) @ Base ./array.jl:657 │││││││││││││ no matching method found `length(::Base.HasLength)`: length(itr::Base.HasLength) ││││││││││││└──────────────────── ││││││││││││┌ _similar_shape(itr::Base.HasLength, ::Base.HasShape) @ Base ./array.jl:658 │││││││││││││┌ axes(A::Base.HasLength) @ Base ./abstractarray.jl:98 ││││││││││││││ no matching method found `size(::Base.HasLength)`: size(A::Base.HasLength) │││││││││││││└──────────────────── ││││││││││││┌ _array_for(::Type{@NamedTuple{region::UnitRange{Int64}, label::Symbol, value}}, itr::Base.HasLength, isz::Nothing) @ Base ./array.jl:673 │││││││││││││ no matching method found `_similar_shape(::Base.HasLength, ::Nothing)`: Base._similar_shape(itr::Base.HasLength, isz::Nothing) ││││││││││││└──────────────────── ``` --- base/array.jl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/base/array.jl b/base/array.jl index 665934b8a3a11..9674bc170ad6e 100644 --- a/base/array.jl +++ b/base/array.jl @@ -641,7 +641,7 @@ julia> collect(Float64, 1:2:5) collect(::Type{T}, itr) where {T} = _collect(T, itr, IteratorSize(itr)) _collect(::Type{T}, itr, isz::Union{HasLength,HasShape}) where {T} = - copyto!(_array_for(T, isz, _similar_shape(itr, isz)), itr) + copyto!(_array_for_inner(T, isz, _similar_shape(itr, isz)), itr) function _collect(::Type{T}, itr, isz::SizeUnknown) where T a = Vector{T}() for x in itr @@ -665,12 +665,12 @@ _similar_for(c::AbstractArray, ::Type{T}, itr, ::HasShape, axs) where {T} = similar(c, T, axs) # make a collection appropriate for collecting `itr::Generator` -_array_for(::Type{T}, ::SizeUnknown, ::Nothing) where {T} = Vector{T}(undef, 0) -_array_for(::Type{T}, ::HasLength, len::Integer) where {T} = Vector{T}(undef, Int(len)) -_array_for(::Type{T}, ::HasShape{N}, axs) where {T,N} = similar(Array{T,N}, axs) +_array_for_inner(::Type{T}, ::SizeUnknown, ::Nothing) where {T} = Vector{T}(undef, 0) +_array_for_inner(::Type{T}, ::HasLength, len::Integer) where {T} = Vector{T}(undef, Int(len)) +_array_for_inner(::Type{T}, ::HasShape{N}, axs) where {T,N} = similar(Array{T,N}, axs) # used by syntax lowering for simple typed comprehensions -_array_for(::Type{T}, itr, isz) where {T} = _array_for(T, isz, _similar_shape(itr, isz)) +_array_for(::Type{T}, itr, isz) where {T} = _array_for_inner(T, isz, _similar_shape(itr, isz)) """ @@ -789,10 +789,10 @@ function collect(itr::Generator) shp = _similar_shape(itr, isz) y = iterate(itr) if y === nothing - return _array_for(et, isz, shp) + return _array_for_inner(et, isz, shp) end v1, st = y - dest = _array_for(typeof(v1), isz, shp) + dest = _array_for_inner(typeof(v1), isz, shp) # The typeassert gives inference a helping hand on the element type and dimensionality # (work-around for #28382) et′ = et <: Type ? Type : et From 01a2eadb0474c395845e66ed3382b52e0c1f1b8f Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Tue, 6 Jan 2026 17:56:43 +0100 Subject: [PATCH 25/83] set VERSION to 1.12.4 (#60539) --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 81f363239f557..89c881bc9cb92 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.12.3 +1.12.4 From 9ef866af2950d0415495859b1e267c530e3d2251 Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Wed, 7 Jan 2026 15:28:20 -0500 Subject: [PATCH 26/83] [Windows][Makefile] Avoid installing `basecompiler-o.a` / `sysbase-o.a` --- Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 259113e430c41..b2d54d0a7a0e5 100644 --- a/Makefile +++ b/Makefile @@ -325,8 +325,7 @@ else ifeq ($(JULIA_BUILD_MODE),debug) -$(INSTALL_M) $(build_libdir)/libjulia-debug.dll.a $(DESTDIR)$(libdir)/ -$(INSTALL_M) $(build_libdir)/libjulia-internal-debug.dll.a $(DESTDIR)$(libdir)/ endif - -$(INSTALL_M) $(wildcard $(build_private_libdir)/*.a) $(DESTDIR)$(private_libdir)/ - -rm -f $(DESTDIR)$(private_libdir)/sys-o.a + -$(INSTALL_M) $(filter-out %-bc.a %-o.a,$(wildcard $(build_private_libdir)/lib*.a)) $(DESTDIR)$(private_libdir)/ -$(INSTALL_M) $(build_bindir)/libopenlibm.dll.a $(DESTDIR)$(libdir)/ -$(INSTALL_M) $(build_libdir)/libssp.dll.a $(DESTDIR)$(libdir)/ From de85ebb2dab5519a2bd337cb62ff7d17dcc8f6c3 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Mon, 29 Dec 2025 15:41:55 -0500 Subject: [PATCH 27/83] =?UTF-8?q?=F0=9F=A4=96=20[backports-release-1.12]?= =?UTF-8?q?=20Bump=20NetworkOptions=20stdlib=20532992f=20=E2=86=92=207034c?= =?UTF-8?q?55=20(#60505)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: NetworkOptions URL: https://github.com/JuliaLang/NetworkOptions.jl.git Stdlib branch: master Julia branch: backports-release-1.12 Old commit: 532992f New commit: 7034c55 Julia version: 1.12.3 NetworkOptions version: 1.3.0 (Does not match) Bump invoked by: @fingolfin Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaLang/NetworkOptions.jl/compare/532992fcc0f1d02df48374969cbae37e34c01360...7034c55dbf52ee959cabd63bcbe656df658f5bda ``` $ git log --oneline 532992f..7034c55 7034c55 Bump actions/checkout from 4 to 5 (#44) 46e14ef Merge pull request #43 from lgoettgens/lg/JET-ca_roots-path_convert ``` Co-authored-by: fingolfin <241512+fingolfin@users.noreply.github.com> --- .../md5 | 1 - .../sha512 | 1 - .../md5 | 1 + .../sha512 | 1 + stdlib/NetworkOptions.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/NetworkOptions-532992fcc0f1d02df48374969cbae37e34c01360.tar.gz/md5 delete mode 100644 deps/checksums/NetworkOptions-532992fcc0f1d02df48374969cbae37e34c01360.tar.gz/sha512 create mode 100644 deps/checksums/NetworkOptions-7034c55dbf52ee959cabd63bcbe656df658f5bda.tar.gz/md5 create mode 100644 deps/checksums/NetworkOptions-7034c55dbf52ee959cabd63bcbe656df658f5bda.tar.gz/sha512 diff --git a/deps/checksums/NetworkOptions-532992fcc0f1d02df48374969cbae37e34c01360.tar.gz/md5 b/deps/checksums/NetworkOptions-532992fcc0f1d02df48374969cbae37e34c01360.tar.gz/md5 deleted file mode 100644 index fbb7d5b86627f..0000000000000 --- a/deps/checksums/NetworkOptions-532992fcc0f1d02df48374969cbae37e34c01360.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -afab093d162a62d5a488894f33d3b396 diff --git a/deps/checksums/NetworkOptions-532992fcc0f1d02df48374969cbae37e34c01360.tar.gz/sha512 b/deps/checksums/NetworkOptions-532992fcc0f1d02df48374969cbae37e34c01360.tar.gz/sha512 deleted file mode 100644 index 146d3a3d1bad8..0000000000000 --- a/deps/checksums/NetworkOptions-532992fcc0f1d02df48374969cbae37e34c01360.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -14b41cc9c93e2f9eeaa9499d65b8c42ee80691cbd533ef6cafabdb6e94c7cf31eee00fb603ca70dfe86930c871419cf17a8f05c0a76bd379a8bbf705b875dfe2 diff --git a/deps/checksums/NetworkOptions-7034c55dbf52ee959cabd63bcbe656df658f5bda.tar.gz/md5 b/deps/checksums/NetworkOptions-7034c55dbf52ee959cabd63bcbe656df658f5bda.tar.gz/md5 new file mode 100644 index 0000000000000..8f918b40b2ffb --- /dev/null +++ b/deps/checksums/NetworkOptions-7034c55dbf52ee959cabd63bcbe656df658f5bda.tar.gz/md5 @@ -0,0 +1 @@ +1fbf59e3052ec0d40a195d935b3d4a96 diff --git a/deps/checksums/NetworkOptions-7034c55dbf52ee959cabd63bcbe656df658f5bda.tar.gz/sha512 b/deps/checksums/NetworkOptions-7034c55dbf52ee959cabd63bcbe656df658f5bda.tar.gz/sha512 new file mode 100644 index 0000000000000..feeb688dcb7e2 --- /dev/null +++ b/deps/checksums/NetworkOptions-7034c55dbf52ee959cabd63bcbe656df658f5bda.tar.gz/sha512 @@ -0,0 +1 @@ +4ec9724062d97a9d400bfb4a672ed5ce52999738ddbc01d2892d97df3fd256fe03bb5ea69f2ebbbbdbfef91edc24d82e54df48f997781eba2c6cd8e1c36d046c diff --git a/stdlib/NetworkOptions.version b/stdlib/NetworkOptions.version index f7cb50a74d106..7a3c0ccd27d3f 100644 --- a/stdlib/NetworkOptions.version +++ b/stdlib/NetworkOptions.version @@ -1,4 +1,4 @@ NETWORKOPTIONS_BRANCH = master -NETWORKOPTIONS_SHA1 = 532992fcc0f1d02df48374969cbae37e34c01360 +NETWORKOPTIONS_SHA1 = 7034c55dbf52ee959cabd63bcbe656df658f5bda NETWORKOPTIONS_GIT_URL := https://github.com/JuliaLang/NetworkOptions.jl.git NETWORKOPTIONS_TAR_URL = https://api.github.com/repos/JuliaLang/NetworkOptions.jl/tarball/$1 From a198393a305dc169e9d997cc457a0cec190c0cc1 Mon Sep 17 00:00:00 2001 From: David Anthoff Date: Tue, 23 Dec 2025 13:44:35 -0800 Subject: [PATCH 28/83] Docs: mention cmd line option for App Installer on Windows (cherry picked from commit 7450aba3420729c112541894056d474b934c1a1c) --- doc/src/manual/installation.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/src/manual/installation.md b/doc/src/manual/installation.md index f45aba2c37a28..5107d30c7286f 100644 --- a/doc/src/manual/installation.md +++ b/doc/src/manual/installation.md @@ -75,7 +75,12 @@ If the Windows Store is blocked on a system, we have an alternative [MSIX App Installer](https://learn.microsoft.com/en-us/windows/msix/app-installer/app-installer-file-overview) based setup. To use the App Installer version, download [this](https://install.julialang.org/Julia.appinstaller) file and open it by -double clicking on it. +double clicking on it. One can also install exactly the same version by executing +the PowerShell command + +``` +Add-AppxPackage -AppInstallerFile https://install.julialang.org/Julia.appinstaller +``` ### MSI Installer (Windows) From 5ae7e55f07a679aae390395be82c6c2186cfb0ca Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Thu, 25 Dec 2025 06:55:14 -0500 Subject: [PATCH 29/83] REPL: fix completion overwriting input after cursor (#60472) (cherry picked from commit b6337dd711a0166bf7574f49b4446d5577cb7d3d) --- stdlib/REPL/src/REPLCompletions.jl | 11 +++++----- stdlib/REPL/test/replcompletions.jl | 32 +++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index cd13f0880d7c4..0a5975179e3a3 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -1025,8 +1025,8 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif if obj !== nothing # Skip leading whitespace inside brackets. i = @something findnext(!isspace, string, first(key)) nextind(string, last(key)) - key = i:last(key) - s = string[intersect(key, 1:pos)] + key = intersect(i:last(key), 1:pos) + s = string[key] matches = find_dict_matches(obj, s) length(matches) == 1 && !closed && (matches[1] *= ']') if length(matches) > 0 @@ -1051,7 +1051,8 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif # "~/example.txt TAB => "/home/user/example.txt" r, closed = find_str(cur) if r !== nothing - s = do_string_unescape(string[intersect(r, 1:pos)]) + r = intersect(r, 1:pos) + s = do_string_unescape(string[r]) ret, success = complete_path_string(s, hint; string_escape=true, dirsep=Sys.iswindows() ? '\\' : '/') if length(ret) == 1 && !closed && close_path_completion(ret[1].path) @@ -1094,8 +1095,8 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif # Keyword argument completion: # foo(ar TAB => keyword arguments like `arg1=` elseif kind(cur) == K"Identifier" - r = char_range(cur) - s = string[intersect(r, 1:pos)] + r = intersect(char_range(cur), 1:pos) + s = string[r] # Return without adding more suggestions if kwargs only complete_keyword_argument!(suggestions, e, s, context_module, arg_pos; shift) && return sort_suggestions(), r, true diff --git a/stdlib/REPL/test/replcompletions.jl b/stdlib/REPL/test/replcompletions.jl index de723cf83d0e7..428a13dd59e79 100644 --- a/stdlib/REPL/test/replcompletions.jl +++ b/stdlib/REPL/test/replcompletions.jl @@ -1492,6 +1492,23 @@ mktempdir() do path @test "$(path_expected)$(sep)foo_dir$(sep)" in c @test "$(path_expected)$(sep)foo_file.txt" in c end + + # Issue #60444: path completion should not delete text after the string (e.g. indexing) + let (c, r, res) = test_complete_pos("f(\"$(path)$(sep)foo|\")") + @test res + @test length(c) == 2 + @test "$(path_expected)$(sep)foo_dir$(sep)" in c + @test "$(path_expected)$(sep)foo_file.txt" in c + end + let (c, r, res) = test_complete_pos("f(\"$(path)$(sep)foo|\")[1]") + @test res + @test length(c) == 2 + @test "$(path_expected)$(sep)foo_dir$(sep)" in c + @test "$(path_expected)$(sep)foo_file.txt" in c + # Range should end at cursor position, not overwrite ")[1]" + pos = findfirst('|', "f(\"$(path)$(sep)foo|\")[1]") - 1 + @test last(r) == pos + end end if Sys.iswindows() @@ -1643,6 +1660,14 @@ test_dict_completion("test_repl_comp_customdict") let s = "test_dict_no_length[" @test REPLCompletions.completions(s, sizeof(s), Main.CompletionFoo) isa Tuple end + + # Issue #60444: completing dict keys should not overwrite input after cursor + let s = "test_dict[\"ab|c\"]" + c, r = test_complete_context_pos(s, Main.CompletionFoo) + @test "\"abc\"" in c + @test "\"abcd\"" in c + @test r == 11:13 # range ends at cursor, not at end of key + end end @testset "completion of string/cmd macros (#22577)" begin @@ -1789,6 +1814,13 @@ end @test hasnokwsuggestions("CompletionFoo.kwtest5('a', 3, 5, unknownsplat...; xy") @test hasnokwsuggestions("CompletionFoo.kwtest5(3; somek") =# + + # Issue #60444: completing keyword arguments should not overwrite input after cursor + let s = "CompletionFoo.kwtest3(a; foob|true)" + c, r = test_complete_pos(s) + @test c == ["foobar="] + @test r == 26:29 + end end # Test completion in context From eb2afda8eee200282d138782c187111962e72814 Mon Sep 17 00:00:00 2001 From: Nicholas Bauer Date: Sat, 27 Dec 2025 08:54:58 -0500 Subject: [PATCH 30/83] Clarify that `cpu_info` times are expressed in milliseconds (#60480) libuv reports times in milliseconds, but the Julia docs and show() use units of 1/Sys.SC_CLK_TCK which is 100 on my laptop. The mismatch might be due to libuv changeset https://github.com/libuv/libuv/commit/37a8affbd319209fd0d0d96ee4e3002c8ecc5076. Fixes #53577 (cherry picked from commit 3d611fddcf02cce3fc8dc518e49f25128b8aaead) --- base/sysinfo.jl | 17 +++++------------ test/sysinfo.jl | 6 ++---- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/base/sysinfo.jl b/base/sysinfo.jl index 56a3681ae35f7..f6c4ed58f5daa 100644 --- a/base/sysinfo.jl +++ b/base/sysinfo.jl @@ -107,8 +107,6 @@ const WORD_SIZE = Core.sizeof(Int) * 8 The number of system "clock ticks" per second, corresponding to `sysconf(_SC_CLK_TCK)` on POSIX systems, or `0` if it is unknown. - -CPU times, e.g. as returned by `Sys.cpu_info()`, are in units of ticks, i.e. units of `1 / Sys.SC_CLK_TCK` seconds if `Sys.SC_CLK_TCK > 0`. """ global SC_CLK_TCK::Clong @@ -202,8 +200,7 @@ The `CPUinfo` type is a mutable struct with the following fields: - `cpu_times!idle::UInt64`: Time spent in idle mode. CPU state shows the CPU time that's not actively being used. - `cpu_times!irq::UInt64`: Time spent handling interrupts. CPU state shows the amount of time the CPU has been servicing hardware interrupts. -The times are in units of `1/Sys.SC_CLK_TCK` seconds if `Sys.SC_CLK_TCK > 0`; otherwise they are in -unknown units. +The times are in units of milliseconds. Note: Included in the detailed system information via `versioninfo(verbose=true)`. """ @@ -224,7 +221,6 @@ CPUinfo(info::UV_cpu_info_t) = CPUinfo(unsafe_string(info.model), info.speed, public CPUinfo function _show_cpuinfo(io::IO, info::Sys.CPUinfo, header::Bool=true, prefix::AbstractString=" ") - tck = SC_CLK_TCK if header println(io, info.model, ": ") print(io, " "^length(prefix)) @@ -232,16 +228,13 @@ function _show_cpuinfo(io::IO, info::Sys.CPUinfo, header::Bool=true, prefix::Abs lpad("sys", 9), " ", lpad("idle", 9), " ", lpad("irq", 9)) end print(io, prefix) - unit = tck > 0 ? " s " : " " - tc = max(tck, 1) + ms_per_s = 1000 + unit = " s " d(i, unit=unit) = lpad(string(round(Int64,i)), 9) * unit print(io, lpad(string(info.speed), 5), " MHz ", - d(info.cpu_times!user / tc), d(info.cpu_times!nice / tc), d(info.cpu_times!sys / tc), - d(info.cpu_times!idle / tc), d(info.cpu_times!irq / tc, tck > 0 ? " s" : " ")) - if tck <= 0 - print(io, "ticks") - end + d(info.cpu_times!user / ms_per_s), d(info.cpu_times!nice / ms_per_s), d(info.cpu_times!sys / ms_per_s), + d(info.cpu_times!idle / ms_per_s), d(info.cpu_times!irq / ms_per_s)) end show(io::IO, ::MIME"text/plain", info::CPUinfo) = _show_cpuinfo(io, info, true, " ") diff --git a/test/sysinfo.jl b/test/sysinfo.jl index f02d8ffe36091..a2af4cd0f5260 100644 --- a/test/sysinfo.jl +++ b/test/sysinfo.jl @@ -65,9 +65,7 @@ end Base.Sys.CPUinfo("Apple M1 Pro", 2400, 0x00000000026784da, 0x0000000000000000, 0x0000000000fda30e, 0x0000000046a731ea, 0x0000000000000000) Base.Sys.CPUinfo("Apple M1 Pro", 2400, 0x00000000017726c0, 0x0000000000000000, 0x00000000009491de, 0x0000000048134f1e, 0x0000000000000000)] - Sys.SC_CLK_TCK, save_SC_CLK_TCK = 100, Sys.SC_CLK_TCK # use platform-independent tick units @test repr(example_cpus[1]) == "Base.Sys.CPUinfo(\"Apple M1 Pro\", 2400, 0x000000000d913b08, 0x0000000000000000, 0x0000000005f4243c, 0x00000000352a550a, 0x0000000000000000)" - @test repr("text/plain", example_cpus[1]) == "Apple M1 Pro: \n speed user nice sys idle irq\n 2400 MHz 2276216 s 0 s 998861 s 8919667 s 0 s" - @test sprint(Sys.cpu_summary, example_cpus) == "Apple M1 Pro: \n speed user nice sys idle irq\n#1 2400 MHz 2276216 s 0 s 998861 s 8919667 s 0 s\n#2 2400 MHz 2275576 s 0 s 978101 s 8962204 s 0 s\n#3 2400 MHz 403386 s 0 s 166224 s 11853624 s 0 s\n#4 2400 MHz 245859 s 0 s 97367 s 12092250 s 0 s\n" - Sys.SC_CLK_TCK = save_SC_CLK_TCK + @test repr("text/plain", example_cpus[1]) == "Apple M1 Pro: \n speed user nice sys idle irq\n 2400 MHz 227622 s 0 s 99886 s 891967 s 0 s " + @test sprint(Sys.cpu_summary, example_cpus) == "Apple M1 Pro: \n speed user nice sys idle irq\n#1 2400 MHz 227622 s 0 s 99886 s 891967 s 0 s \n#2 2400 MHz 227558 s 0 s 97810 s 896220 s 0 s \n#3 2400 MHz 40339 s 0 s 16622 s 1185362 s 0 s \n#4 2400 MHz 24586 s 0 s 9737 s 1209225 s 0 s \n" end From 387dd934500943d5f2361120ad549e260a9554e5 Mon Sep 17 00:00:00 2001 From: N5N3 <2642243996@qq.com> Date: Mon, 29 Dec 2025 19:01:03 +0800 Subject: [PATCH 31/83] Fix `@allocated 1 .+ 1` (#60494) Dot operators (e.g., .+, .-) are lowered to `BroadcastFunction` and do not have corresponding function definitions. Fix the regression by adding the needed wrapper. Test added. --------- Co-authored-by: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> (cherry picked from commit 7ba24a71da45e0f2aa7f7307753620c59269700a) --- base/timing.jl | 8 ++++++++ test/misc.jl | 3 +++ 2 files changed, 11 insertions(+) diff --git a/base/timing.jl b/base/timing.jl index e937d396a52a2..230849c7eb3d7 100644 --- a/base/timing.jl +++ b/base/timing.jl @@ -498,6 +498,14 @@ function is_simply_call(@nospecialize ex) Meta.isexpr(a, :..., 1) && is_simple_atom(a.args[1]) && continue return false end + # Ensure Expr(:call, .+, ...) get wrapped + if ex.args[1] isa Symbol + sa = String(ex.args[1]::Symbol) + startswith(sa, ".") && + !endswith(sa, ".") && + isoperator(Symbol(sa[2:end])) && + return false + end return true end diff --git a/test/misc.jl b/test/misc.jl index 8d6ee39715303..f830913d21098 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -1542,6 +1542,9 @@ end @allocated _x = 1+2 @test _x === 3 + # test `@allocated` works for dotted operations + @test (@allocated 1 .+ 1) == 0 + n, m = 10, 20 X = rand(n, m) treshape59278(X, n, m) From 1ed5bdf7655a3b8e8f9dc935d564c164ab5c1e14 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 29 Dec 2025 18:36:46 +0100 Subject: [PATCH 32/83] Fix JET warning by avoiding recursion in `getproperty(::DirEntry)` (#60506) This lead to JET warnings in e.g. `realpath`. I would say even better would be to avoid this `getproperty` method altogether. I have an alternative patch which adds a `path(::DirEntry)` method and changes code in REPL and tests to avoid it. (cherry picked from commit a4d21299053d0e140561a7969694b93751c9d312) --- base/file.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/file.jl b/base/file.jl index 7c2d8ebe86de8..cece850ea265b 100644 --- a/base/file.jl +++ b/base/file.jl @@ -1059,7 +1059,7 @@ struct DirEntry end function Base.getproperty(obj::DirEntry, p::Symbol) if p === :path - return joinpath(obj.dir, obj.name) + return joinpath(getfield(obj, :dir), getfield(obj, :name)) else return getfield(obj, p) end From 89dc101c04c8366ab567d786430dc9b5db0aacc5 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 29 Dec 2025 19:11:53 +0100 Subject: [PATCH 33/83] Fix JET warning in `artifact_meta` (#60507) `unpack_platform` might return nothing in case of an error. Together with PR #60506 and my previous changes, when applied to release-1.12, the JET report for GAP.jl is now free of reports. Well, if I filter out certain "unavoidable issues": ```julia using Revise, JET, AbstractAlgebra, GAP struct AnyFrameMethod <: ReportMatcher m::Union{Function,Method,Symbol} end function JET.match_report(matcher::AnyFrameMethod, @nospecialize(report::JET.InferenceErrorReport)) # check all VirtualFrames in the VirtualStackTrace for a match to the specified method m = matcher.m if m isa Symbol return any(vf -> vf.linfo.def.name === m, report.vst) elseif m isa Method return any(vf -> vf.linfo.def === m, report.vst) else # if m isa Function return any(vf -> vf.linfo.def in methods(m), report.vst) end end report_package(GAP; ignored_modules=[AnyFrameMethod(:is_loaded_directly)]) ``` (cherry picked from commit 8123a5cb8256ce2e96d34a14e8200e580e3b8f50) --- stdlib/Artifacts/src/Artifacts.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/Artifacts/src/Artifacts.jl b/stdlib/Artifacts/src/Artifacts.jl index 0227d9532a49c..79cb05e86e354 100644 --- a/stdlib/Artifacts/src/Artifacts.jl +++ b/stdlib/Artifacts/src/Artifacts.jl @@ -410,7 +410,7 @@ function artifact_meta(name::String, artifact_dict::Dict, artifacts_toml::String dl_dict = Dict{Platform,Dict{String,Any}}() for x in meta x = x::Dict{String, Any} - dl_dict[unpack_platform(x, name, artifacts_toml)] = x + dl_dict[unpack_platform(x, name, artifacts_toml)::Platform] = x end meta = select_platform(dl_dict, platform) # If it's NOT a dict, complain From e7b2b231a5349582406950162806c341bcdbc6ba Mon Sep 17 00:00:00 2001 From: Nathan Zimmerberg <39104088+nhz2@users.noreply.github.com> Date: Mon, 12 Jan 2026 11:08:14 -0500 Subject: [PATCH 34/83] [backports-release-1.12] Fix build with USE_SYSTEM_P7ZIP=1 for 1.12 (#60644) fix #60596 for Julia 1.12 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b2d54d0a7a0e5..fd84ad0e7b033 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ default: $(JULIA_BUILD_MODE) # contains either "debug" or "release" all: debug release # sort is used to remove potential duplicates -DIRS := $(sort $(build_bindir) $(build_depsbindir) $(build_libdir) $(build_private_libdir) $(build_libexecdir) $(build_includedir) $(build_includedir)/julia $(build_sysconfdir)/julia $(build_datarootdir)/julia $(build_datarootdir)/julia/stdlib $(build_man1dir)) +DIRS := $(sort $(build_bindir) $(build_depsbindir) $(build_libdir) $(build_private_libdir) $(build_private_libexecdir) $(build_libexecdir) $(build_includedir) $(build_includedir)/julia $(build_sysconfdir)/julia $(build_datarootdir)/julia $(build_datarootdir)/julia/stdlib $(build_man1dir)) ifneq ($(BUILDROOT),$(JULIAHOME)) BUILDDIRS := $(BUILDROOT) $(addprefix $(BUILDROOT)/,base src src/flisp src/support src/clangsa cli doc deps stdlib test test/clangsa test/embedding test/gcext test/llvmpasses) BUILDDIRMAKE := $(addsuffix /Makefile,$(BUILDDIRS)) $(BUILDROOT)/sysimage.mk $(BUILDROOT)/pkgimage.mk From a6c2a276abd4412f563e2e0ac39a9e5f1834bc4d Mon Sep 17 00:00:00 2001 From: William Moses Date: Wed, 14 Jan 2026 16:58:23 -0600 Subject: [PATCH 35/83] 1.12: add getter for global variable pointer matching jlvalue (#60685) --- src/aotcompile.cpp | 16 ++++++++++++++++ src/codegen-stubs.c | 1 + src/jl_exported_funcs.inc | 1 + src/julia_internal.h | 1 + 4 files changed, 19 insertions(+) diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 6009bd435534c..df8a825df3ffe 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -124,6 +124,22 @@ extern "C" JL_DLLEXPORT_CODEGEN void jl_get_llvm_gvs_impl(void *native_code, memcpy(data, value_map.data(), *num_elements * sizeof(void *)); } +extern "C" JL_DLLEXPORT_CODEGEN void jl_get_llvm_gvs_globals_impl(void *native_code, + size_t *num_elements, void **data) +{ + // map a memory location (jl_value_t or jl_binding_t) to a GlobalVariable + jl_native_code_desc_t *desc = (jl_native_code_desc_t *)native_code; + auto &value_map = desc->jl_sysimg_gvars; + + if (data == NULL) { + *num_elements = value_map.size(); + return; + } + + assert(*num_elements == value_map.size()); + memcpy(data, value_map.data(), *num_elements * sizeof(void *)); +} + extern "C" JL_DLLEXPORT_CODEGEN void jl_get_llvm_external_fns_impl(void *native_code, size_t *num_elements, jl_code_instance_t *data) diff --git a/src/codegen-stubs.c b/src/codegen-stubs.c index 04f38fb9091be..e35fdfddfbab9 100644 --- a/src/codegen-stubs.c +++ b/src/codegen-stubs.c @@ -14,6 +14,7 @@ JL_DLLEXPORT void jl_dump_native_fallback(void *native_code, const char *bc_fname, const char *unopt_bc_fname, const char *obj_fname, const char *asm_fname, ios_t *z, ios_t *s) UNAVAILABLE JL_DLLEXPORT void jl_get_llvm_gvs_fallback(void *native_code, arraylist_t *gvs) UNAVAILABLE +JL_DLLEXPORT void jl_get_llvm_gvs_globals_fallback(void *native_code, arraylist_t *gvs) UNAVAILABLE JL_DLLEXPORT void jl_get_llvm_external_fns_fallback(void *native_code, arraylist_t *gvs) UNAVAILABLE JL_DLLEXPORT void jl_get_llvm_mis_fallback(void *native_code, arraylist_t* MIs) UNAVAILABLE diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index 61420c7306de9..8d2c1d391cb3c 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -523,6 +523,7 @@ YY(jl_get_LLVM_VERSION) \ YY(jl_dump_native) \ YY(jl_get_llvm_gvs) \ + YY(jl_get_llvm_gvs_globals) \ YY(jl_get_llvm_external_fns) \ YY(jl_get_llvm_mis) \ YY(jl_dump_function_asm) \ diff --git a/src/julia_internal.h b/src/julia_internal.h index c9e1b0e204df6..a74fcfb7903d3 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -2057,6 +2057,7 @@ JL_DLLIMPORT void jl_dump_native(void *native_code, const char *bc_fname, const char *unopt_bc_fname, const char *obj_fname, const char *asm_fname, ios_t *z, ios_t *s, jl_emission_params_t *params); JL_DLLIMPORT void jl_get_llvm_gvs(void *native_code, size_t *num_els, void **gvs); +JL_DLLIMPORT void jl_get_llvm_gvs_globals(void *native_code, size_t *num_els, void **gvs); JL_DLLIMPORT void jl_get_llvm_external_fns(void *native_code, size_t *num_els, jl_code_instance_t *gvs); JL_DLLIMPORT void jl_get_function_id(void *native_code, jl_code_instance_t *ncode, From ab6dd0a0c5b286ed33a934fd74f6d817973122a3 Mon Sep 17 00:00:00 2001 From: Oscar Smith Date: Wed, 14 Jan 2026 18:19:31 -0500 Subject: [PATCH 36/83] Backport `@fastmath x^2` inlining regression to 1.12 (#60686) This isn't a direct backport of https://github.com/JuliaLang/julia/pull/60640/changes because because `llvm.powi.f16.i32` is very broken on LLVM 18 (at least for targets without hardware fp16 support like x86). This is only a performance backport, but it is a pretty important regression that was introduced in 1.12. --- base/fastmath.jl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/base/fastmath.jl b/base/fastmath.jl index ed686fb92bf34..afae504a8830f 100644 --- a/base/fastmath.jl +++ b/base/fastmath.jl @@ -297,12 +297,13 @@ exp10_fast(x::Union{Float32,Float64}) = Base.Math.exp10_fast(x) # builtins -@inline function pow_fast(x::Float64, y::Integer) +@inline function pow_fast(x::Union{Float32, Float64}, y::Integer) z = y % Int32 z == y ? pow_fast(x, z) : x^y end -pow_fast(x::Float32, y::Integer) = x^y -pow_fast(x::Float64, y::Int32) = ccall("llvm.powi.f64.i32", llvmcall, Float64, (Float64, Int32), x, y) +@inline pow_fast(x::Float16, y::Integer) = Float16(pow_fast(Float32(x), y)) +pow_fast(x::Float64, y::Int32) = ccall("llvm.powi", llvmcall, Float64, (Float64, Int32), x, y) +pow_fast(x::Float32, y::Int32) = ccall("llvm.powi", llvmcall, Float32, (Float32, Int32), x, y) pow_fast(x::FloatTypes, ::Val{p}) where {p} = pow_fast(x, p) # inlines already via llvm.powi @inline pow_fast(x, v::Val) = Base.literal_pow(^, x, v) From 634170eb527cf211799bc16c11e6d0fc38c4befa Mon Sep 17 00:00:00 2001 From: Nathan Zimmerberg <39104088+nhz2@users.noreply.github.com> Date: Sat, 10 Jan 2026 19:08:05 -0500 Subject: [PATCH 37/83] Fix build with USE_SYSTEM_P7ZIP=1 (#60623) (cherry picked from commit 657273aebc81d289eaf888f5bcccd6a4e0fce44b) --- base/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/Makefile b/base/Makefile index eb36d6d0a4319..0f7767e0aef37 100644 --- a/base/Makefile +++ b/base/Makefile @@ -183,14 +183,14 @@ endif endef # libexec executables -symlink_p7zip: $(build_bindir)/7z$(EXE) +symlink_p7zip: $(build_private_libexecdir)/7z$(EXE) ifneq ($(USE_SYSTEM_P7ZIP),0) SYMLINK_SYSTEM_LIBRARIES += symlink_p7zip 7Z_PATH := $(shell which 7z$(EXE)) endif -$(build_bindir)/7z$(EXE): +$(build_private_libexecdir)/7z$(EXE): [ -e "$(7Z_PATH)" ] && \ rm -f "$@" && \ ln -sf "$(7Z_PATH)" "$@" From e1e955abe00c0ecba3c993c38f21c7e815bab4b2 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Wed, 14 Jan 2026 17:42:43 -0300 Subject: [PATCH 38/83] Don't set the owner of the string needlessly. (#60601) This might cause double frees/use after frees. Found on the mimalloc PR (cherry picked from commit 06def894dc0281a9582ec9138960edf60fb262e8) --- src/gc-stock.c | 2 +- src/genericmemory.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/gc-stock.c b/src/gc-stock.c index 55f31b26679ff..52759a2febc61 100644 --- a/src/gc-stock.c +++ b/src/gc-stock.c @@ -629,7 +629,7 @@ void jl_gc_reset_alloc_count(void) JL_NOTSAFEPOINT static void jl_gc_free_memory(jl_genericmemory_t *m, int isaligned) JL_NOTSAFEPOINT { assert(jl_is_genericmemory(m)); - assert(jl_genericmemory_how(m) == 1 || jl_genericmemory_how(m) == 2); + assert(jl_genericmemory_how(m) == 1); char *d = (char*)m->ptr; size_t freed_bytes = memory_block_usable_size(d, isaligned); assert(freed_bytes != 0); diff --git a/src/genericmemory.c b/src/genericmemory.c index 32adc1add3d06..fbdccca2174fa 100644 --- a/src/genericmemory.c +++ b/src/genericmemory.c @@ -200,7 +200,6 @@ JL_DLLEXPORT jl_value_t *jl_genericmemory_to_string(jl_genericmemory_t *m, size_ m->length = 0; if (how != 0) { jl_value_t *o = jl_genericmemory_data_owner_field(m); - jl_genericmemory_data_owner_field(m) = NULL; if (how == 3 && // implies jl_is_string(o) ((mlength + sizeof(void*) + 1 <= GC_MAX_SZCLASS) == (len + sizeof(void*) + 1 <= GC_MAX_SZCLASS))) { if (jl_string_data(o)[len] != '\0') From b2bc423a2dd45da0e4c10de2d5f9cc12e66fdbad Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 15 Jan 2026 00:23:55 -0500 Subject: [PATCH 39/83] add wb_back on all task switch paths (#60617) Since this task's stack or scope field could have been modified after it was marked by an incremental collection (and not just for copy stacks), move the barrier back unconditionally here. --------- Co-authored-by: Valentin Churavy Co-authored-by: Jeff Bezanson (cherry picked from commit 14ca1abc7237fc586d71d8b1b2c5a2d08bc2276e) --- src/task.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/task.c b/src/task.c index 019a301b1f062..735af58b8fd35 100644 --- a/src/task.c +++ b/src/task.c @@ -203,10 +203,6 @@ static void NOINLINE save_stack(jl_ptls_t ptls, jl_task_t *lastt, jl_task_t **pt lastt->ctx.copy_stack = nb; lastt->sticky = 1; memcpy_stack_a16((uint64_t*)buf, (uint64_t*)frame_addr, nb); - // this task's stack could have been modified after - // it was marked by an incremental collection - // move the barrier back instead of walking it again here - jl_gc_wb_back(lastt); } JL_NO_ASAN static void NOINLINE JL_NORETURN restore_stack(jl_ucontext_t *t, jl_ptls_t ptls, char *p) @@ -504,6 +500,12 @@ JL_NO_ASAN static void ctx_switch(jl_task_t *lastt) lastt->ctx.ctx = &lasttstate.ctx; } } + // this task's stack or scope field could have been modified after + // it was marked by an incremental collection + // move the barrier back instead of walking the shadow stack again here to check if that is required + // even if killed (dropping the stack) and just the scope field matters, + // let the gc figure that out next time it does a quick mark + jl_gc_wb_back(lastt); // set up global state for new task and clear global state for old task t->ptls = ptls; From 3c92c840c8ff839586a44c1f1e24483bcdabfe21 Mon Sep 17 00:00:00 2001 From: "William S. Moses" Date: Wed, 14 Jan 2026 21:45:30 -0600 Subject: [PATCH 40/83] [LLVMAllocOpt] Preserve metadata lowering an alloca (cherry picked from commit 346b4e1cb6dedc520cd7b16430326d1dd303163f) --- src/llvm-alloc-opt.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/llvm-alloc-opt.cpp b/src/llvm-alloc-opt.cpp index ce1d22f42d0ae..7005d4329c9fc 100644 --- a/src/llvm-alloc-opt.cpp +++ b/src/llvm-alloc-opt.cpp @@ -701,6 +701,7 @@ void Optimizer::moveToStack(CallInst *orig_inst, size_t sz, bool has_ref, AllocF initializeAlloca(builder, buff, allockind); } Instruction *new_inst = cast(ptr); + new_inst->copyMetadata(*orig_inst); new_inst->takeName(orig_inst); auto simple_replace = [&] (Instruction *orig_i, Instruction *new_i) { From 03eeb808609d35d1ab25f19153aee916371777a8 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Fri, 16 Jan 2026 05:13:42 -0500 Subject: [PATCH 41/83] =?UTF-8?q?=F0=9F=A4=96=20[backports-release-1.12]?= =?UTF-8?q?=20Bump=20SparseArrays=20stdlib=20f81a30d=20=E2=86=92=202376bf8?= =?UTF-8?q?=20(#60703)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: SparseArrays URL: https://github.com/JuliaSparse/SparseArrays.jl.git Stdlib branch: release-1.12 Julia branch: backports-release-1.12 Old commit: f81a30d New commit: 2376bf8 Julia version: 1.12.4 SparseArrays version: 1.12.0 (Does not match) Bump invoked by: @dkarrasch Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaSparse/SparseArrays.jl/compare/f81a30d962b03d4048b26439d60979673e343b67...2376bf8734754c5dd4264186299ae6839ab7783f ``` $ git log --oneline f81a30d..2376bf8 2376bf8 Backports to v1.12.5 (#669) e545b39 Update CI workflow for Julia and checkout action (#659) e129aea Separate out tests for the GPL build and do not run them when GPL libs are not present (#658) ``` Co-authored-by: dkarrasch <26658441+dkarrasch@users.noreply.github.com> --- .../md5 | 1 + .../sha512 | 1 + .../md5 | 1 - .../sha512 | 1 - stdlib/SparseArrays.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/SparseArrays-2376bf8734754c5dd4264186299ae6839ab7783f.tar.gz/md5 create mode 100644 deps/checksums/SparseArrays-2376bf8734754c5dd4264186299ae6839ab7783f.tar.gz/sha512 delete mode 100644 deps/checksums/SparseArrays-f81a30d962b03d4048b26439d60979673e343b67.tar.gz/md5 delete mode 100644 deps/checksums/SparseArrays-f81a30d962b03d4048b26439d60979673e343b67.tar.gz/sha512 diff --git a/deps/checksums/SparseArrays-2376bf8734754c5dd4264186299ae6839ab7783f.tar.gz/md5 b/deps/checksums/SparseArrays-2376bf8734754c5dd4264186299ae6839ab7783f.tar.gz/md5 new file mode 100644 index 0000000000000..233004ebc84fe --- /dev/null +++ b/deps/checksums/SparseArrays-2376bf8734754c5dd4264186299ae6839ab7783f.tar.gz/md5 @@ -0,0 +1 @@ +059aef1395d4160561236167379af7ae diff --git a/deps/checksums/SparseArrays-2376bf8734754c5dd4264186299ae6839ab7783f.tar.gz/sha512 b/deps/checksums/SparseArrays-2376bf8734754c5dd4264186299ae6839ab7783f.tar.gz/sha512 new file mode 100644 index 0000000000000..ea773676bed87 --- /dev/null +++ b/deps/checksums/SparseArrays-2376bf8734754c5dd4264186299ae6839ab7783f.tar.gz/sha512 @@ -0,0 +1 @@ +69015dbc54d0d374b89eea2464eafd0aae461ad819965ad5745fc5ce50cf9519eb4d4024209184a90f2704873a96a0fd3586bf354a036c4c44452141d5535f43 diff --git a/deps/checksums/SparseArrays-f81a30d962b03d4048b26439d60979673e343b67.tar.gz/md5 b/deps/checksums/SparseArrays-f81a30d962b03d4048b26439d60979673e343b67.tar.gz/md5 deleted file mode 100644 index 372c4735d1c07..0000000000000 --- a/deps/checksums/SparseArrays-f81a30d962b03d4048b26439d60979673e343b67.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -230a4d9544d2cec7c4adf9a50d228345 diff --git a/deps/checksums/SparseArrays-f81a30d962b03d4048b26439d60979673e343b67.tar.gz/sha512 b/deps/checksums/SparseArrays-f81a30d962b03d4048b26439d60979673e343b67.tar.gz/sha512 deleted file mode 100644 index 6f1838c5bb750..0000000000000 --- a/deps/checksums/SparseArrays-f81a30d962b03d4048b26439d60979673e343b67.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -d66a3b6e032af45b78f71d8c5851c3e6fe1c5159f4c4428b64f1f6a52a111a488a9cec8f702a9e5de96593f5d4735f7490ae6c33eee7155b31f743b82aebd38b diff --git a/stdlib/SparseArrays.version b/stdlib/SparseArrays.version index 98763ae71e777..0e282a70c0acb 100644 --- a/stdlib/SparseArrays.version +++ b/stdlib/SparseArrays.version @@ -1,4 +1,4 @@ SPARSEARRAYS_BRANCH = release-1.12 -SPARSEARRAYS_SHA1 = f81a30d962b03d4048b26439d60979673e343b67 +SPARSEARRAYS_SHA1 = 2376bf8734754c5dd4264186299ae6839ab7783f SPARSEARRAYS_GIT_URL := https://github.com/JuliaSparse/SparseArrays.jl.git SPARSEARRAYS_TAR_URL = https://api.github.com/repos/JuliaSparse/SparseArrays.jl/tarball/$1 From d6a0cd2009d6fa81c0739bb89b2a3ae38e2d6d14 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Fri, 16 Jan 2026 10:23:52 -0300 Subject: [PATCH 42/83] Remove potential unitialized memory in the GC stack (#60651) (cherry picked from commit f9d461f4669d44dea86bed497b9498054d998988) --- src/codegen.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/codegen.cpp b/src/codegen.cpp index 8f0644c0cff7f..67d2d134f3ec0 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2305,6 +2305,19 @@ static inline jl_cgval_t value_to_pointer(jl_codectx_t &ctx, const jl_cgval_t &v Align align(julia_alignment(v.typ)); Type *ty = julia_type_to_llvm(ctx, v.typ); AllocaInst *loc = emit_static_alloca(ctx, ty, align); + jl_datatype_t *dt = (jl_datatype_t *)v.typ; + size_t npointers = dt->layout->first_ptr >= 0 ? dt->layout->npointers : 0; + if (npointers > 0) { + auto InsertPoint = ctx.builder.saveIP(); + ctx.builder.SetInsertPoint(ctx.topalloca->getParent(), ++ctx.topalloca->getIterator()); + for (size_t i = 0; i < npointers; i++) { + // make sure these are nullptr early from LLVM's perspective, in case it decides to SROA it + Value *ptr_field = emit_ptrgep(ctx, loc, jl_ptr_offset(dt, i) * sizeof(void *)); + ctx.builder.CreateAlignedStore( + Constant::getNullValue(ctx.types().T_prjlvalue), ptr_field, Align(sizeof(void *))); + } + ctx.builder.restoreIP(InsertPoint); + } auto tbaa = v.V == nullptr ? ctx.tbaa().tbaa_gcframe : ctx.tbaa().tbaa_stack; auto stack_ai = jl_aliasinfo_t::fromTBAA(ctx, tbaa); recombine_value(ctx, v, loc, stack_ai, align, false); From a7ec7a2b18bad28340175575ae8adaf69c5c19e7 Mon Sep 17 00:00:00 2001 From: Dilum Aluthge Date: Fri, 16 Jan 2026 13:25:31 -0500 Subject: [PATCH 43/83] Print `full_name` after precompiling extension (#60456) (cherry picked from commit 3690b1e09306e146718002db9b96edfb01253c72) Note: This cherry-pick required manual conflict-resolution. --- base/precompilation.jl | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/base/precompilation.jl b/base/precompilation.jl index 45634d877115f..27c380a3d14af 100644 --- a/base/precompilation.jl +++ b/base/precompilation.jl @@ -845,7 +845,7 @@ function _precompilepkgs(pkgs::Union{Vector{String}, Vector{PkgId}}, write(get!(IOBuffer, std_outputs, pkg_config), str) if !in(pkg_config, taskwaiting) && occursin("waiting for IO to finish", str) !fancyprint && @lock print_lock begin - println(io, pkg.name, color_string(" Waiting for background task / IO / timer.", Base.warn_color())) + println(io, full_name(ext_to_parent, pkg), color_string(" Waiting for background task / IO / timer.", Base.warn_color())) end push!(taskwaiting, pkg_config) end @@ -1015,7 +1015,8 @@ function _precompilepkgs(pkgs::Union{Vector{String}, Vector{PkgId}}, try # allows processes to wait if another process is precompiling a given package to # a functionally identical package cache (except for preferences, which may differ) - t = @elapsed ret = precompile_pkgs_maybe_cachefile_lock(io, print_lock, fancyprint, pkg_config, pkgspidlocked, hascolor, parallel_limiter, ignore_loaded) do + fullname = full_name(ext_to_parent, pkg) + t = @elapsed ret = precompile_pkgs_maybe_cachefile_lock(io, print_lock, fancyprint, pkg_config, pkgspidlocked, hascolor, parallel_limiter, ignore_loaded, fullname) do Base.with_logger(Base.NullLogger()) do # whether to respect already loaded dependency versions keep_loaded_modules = !ignore_loaded @@ -1094,7 +1095,7 @@ function _precompilepkgs(pkgs::Union{Vector{String}, Vector{PkgId}}, str = sprint(context=io) do iostr if !quick_exit if fancyprint # replace the progress bar - what = isempty(requested_pkgids) ? "packages finished." : "$(join((p.name for p in requested_pkgids), ", ", " and ")) finished." + what = isempty(requested_pkgids) ? "packages finished." : "$(join((full_name(ext_to_parent, p) for p in requested_pkgids), ", ", " and ")) finished." printpkgstyle(iostr, :Precompiling, what) end plural = length(configs) > 1 ? "dependency configurations" : ndeps == 1 ? "dependency" : "dependencies" @@ -1157,7 +1158,7 @@ function _precompilepkgs(pkgs::Union{Vector{String}, Vector{PkgId}}, for (pkg_config, err) in failed_deps dep, config = pkg_config if strict || (dep in project_deps) - print(err_str, "\n", dep.name, " ") + print(err_str, "\n", full_name(ext_to_parent, dep), " ") for cfg in config[1] print(err_str, cfg, " ") end @@ -1205,7 +1206,7 @@ function _color_string(cstr::String, col::Union{Int64, Symbol}, hascolor) end # Can be merged with `maybe_cachefile_lock` in loading? -function precompile_pkgs_maybe_cachefile_lock(f, io::IO, print_lock::ReentrantLock, fancyprint::Bool, pkg_config, pkgspidlocked, hascolor, parallel_limiter::Base.Semaphore, ignore_loaded::Bool) +function precompile_pkgs_maybe_cachefile_lock(f, io::IO, print_lock::ReentrantLock, fancyprint::Bool, pkg_config, pkgspidlocked, hascolor, parallel_limiter::Base.Semaphore, ignore_loaded::Bool, fullname) if !(isdefined(Base, :mkpidlock_hook) && isdefined(Base, :trymkpidlock_hook) && Base.isdefined(Base, :parse_pidfile_hook)) return f() end @@ -1226,7 +1227,7 @@ function precompile_pkgs_maybe_cachefile_lock(f, io::IO, print_lock::ReentrantLo "another machine (hostname: $hostname, pid: $pid, pidfile: $pidfile)" end !fancyprint && @lock print_lock begin - println(io, " ", pkg.name, _color_string(" Being precompiled by $(pkgspidlocked[pkg_config])", Base.info_color(), hascolor)) + println(io, " ", fullname, _color_string(" Being precompiled by $(pkgspidlocked[pkg_config])", Base.info_color(), hascolor)) end Base.release(parallel_limiter) # release so other work can be done while waiting try From 30e745e53d439cdd4ae6d80eef7b50f37a4b567f Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Tue, 16 Dec 2025 17:00:31 -0300 Subject: [PATCH 44/83] Add heap sized based full gc heuristic (#60376) (cherry picked from commit 14945c0a717693b077ea555e7b1d8aa5b03ec61a) --- base/timing.jl | 2 +- src/gc-stock.c | 42 ++++++++++++++++++++++++++---------------- src/gc-stock.h | 3 ++- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/base/timing.jl b/base/timing.jl index 230849c7eb3d7..98f4f06cbcd47 100644 --- a/base/timing.jl +++ b/base/timing.jl @@ -113,7 +113,7 @@ end @static if Base.USING_STOCK_GC # must be kept in sync with `src/gc-stock.h`` const FULL_SWEEP_REASONS = [:FULL_SWEEP_REASON_SWEEP_ALWAYS_FULL, :FULL_SWEEP_REASON_FORCED_FULL_SWEEP, - :FULL_SWEEP_REASON_USER_MAX_EXCEEDED, :FULL_SWEEP_REASON_LARGE_PROMOTION_RATE] + :FULL_SWEEP_REASON_USER_MAX_EXCEEDED, :FULL_SWEEP_REASON_LARGE_PROMOTION_RATE, :FULL_SWEEP_REASON_LARGE_HEAP_GROWTH] end """ diff --git a/src/gc-stock.c b/src/gc-stock.c index 52759a2febc61..a95dc5f731a5b 100644 --- a/src/gc-stock.c +++ b/src/gc-stock.c @@ -197,6 +197,7 @@ static int mark_reset_age = 0; static int64_t scanned_bytes; // young bytes scanned while marking static int64_t perm_scanned_bytes; // old bytes scanned while marking +static int64_t heap_size_after_last_full_gc = 0; int prev_sweep_full = 1; int current_sweep_full = 0; int next_sweep_full = 0; @@ -2232,13 +2233,13 @@ JL_DLLEXPORT void jl_gc_mark_queue_objarray(jl_ptls_t ptls, jl_value_t *parent, // `_new_obj` has its lowest bit tagged if it's in the remset (in which case we shouldn't update page metadata) FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_new_obj) { - int meta_updated = (uintptr_t)_new_obj & GC_REMSET_PTR_TAG; + int remset_object = (uintptr_t)_new_obj & GC_REMSET_PTR_TAG; jl_value_t *new_obj = (jl_value_t *)((uintptr_t)_new_obj & ~(uintptr_t)GC_REMSET_PTR_TAG); mark_obj: { jl_taggedvalue_t *o = jl_astaggedvalue(new_obj); uintptr_t vtag = o->header & ~(uintptr_t)0xf; uint8_t bits = (gc_old(o->header) && !mark_reset_age) ? GC_OLD_MARKED : GC_MARKED; - int update_meta = __likely(!meta_updated && !gc_verifying); + int update_meta = __likely(!remset_object && !gc_verifying); int foreign_alloc = 0; if (update_meta && o->bits.in_image) { foreign_alloc = 1; @@ -2338,7 +2339,7 @@ FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_ uintptr_t nptr = (npointers << 2) | 1 | bits; new_obj = gc_mark_obj8(ptls, obj8_parent, obj8_begin, obj8_end, nptr); if (new_obj != NULL) { - if (!meta_updated) + if (!remset_object) goto mark_obj; else gc_ptr_queue_push(mq, new_obj); @@ -2460,7 +2461,7 @@ FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_ assert(obj8_begin < obj8_end); new_obj = gc_mark_obj8(ptls, obj8_parent, obj8_begin, obj8_end, nptr); if (new_obj != NULL) { - if (!meta_updated) + if (!remset_object) goto mark_obj; else gc_ptr_queue_push(mq, new_obj); @@ -2473,7 +2474,7 @@ FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_ assert(obj16_begin < obj16_end); new_obj = gc_mark_obj16(ptls, obj16_parent, obj16_begin, obj16_end, nptr); if (new_obj != NULL) { - if (!meta_updated) + if (!remset_object) goto mark_obj; else gc_ptr_queue_push(mq, new_obj); @@ -2488,7 +2489,7 @@ FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_ assert(obj32_begin < obj32_end); new_obj = gc_mark_obj32(ptls, obj32_parent, obj32_begin, obj32_end, nptr); if (new_obj != NULL) { - if (!meta_updated) + if (!remset_object) goto mark_obj; else gc_ptr_queue_push(mq, new_obj); @@ -3036,7 +3037,6 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) uint64_t gc_start_time = jl_hrtime(); uint64_t mutator_time = gc_end_time == 0 ? old_mut_time : gc_start_time - gc_end_time; uint64_t before_free_heap_size = jl_atomic_load_relaxed(&gc_heap_stats.heap_size); - int64_t last_perm_scanned_bytes = perm_scanned_bytes; uint64_t start_mark_time = jl_hrtime(); JL_PROBE_GC_MARK_BEGIN(); { @@ -3130,8 +3130,9 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) gc_stats_all_pool(); gc_stats_big_obj(); gc_num.total_allocd += gc_num.allocd; - if (!prev_sweep_full) - promoted_bytes += perm_scanned_bytes - last_perm_scanned_bytes; + // promoted_bytes are all the new bytes scanned that got promoted to old but that have never seen a full GC as old + promoted_bytes += scanned_bytes; + scanned_bytes = 0; // 4. next collection decision int remset_nptr = 0; int sweep_full = next_sweep_full; @@ -3157,13 +3158,6 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) recollect = 1; gc_count_full_sweep_reason(FULL_SWEEP_REASON_FORCED_FULL_SWEEP); } - if (sweep_full) { - // these are the difference between the number of gc-perm bytes scanned - // on the first collection after sweep_full, and the current scan - perm_scanned_bytes = 0; - promoted_bytes = 0; - } - scanned_bytes = 0; // 5. start sweeping uint64_t start_sweep_time = jl_hrtime(); JL_PROBE_GC_SWEEP_BEGIN(sweep_full); @@ -3295,7 +3289,19 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) target_heap = jl_atomic_load_relaxed(&gc_heap_stats.heap_target); } + if (sweep_full) { + // these are the difference between the number of gc-perm bytes scanned + // on the first collection after sweep_full, and the current scan + perm_scanned_bytes = 0; + promoted_bytes = 0; + heap_size_after_last_full_gc = jl_atomic_load_relaxed(&gc_heap_stats.heap_size); + } + // We want to trigger full GCs either if the heap size has grown a lot since the last full GC. + // For this we use the overallocation function to see what a reasonable rate of growth is, + // or if there is too much memory that has not seen a full GC after being promoted to old. double old_ratio = (double)promoted_bytes/(double)heap_size; + double expected_heap_size = overallocation(heap_size_after_last_full_gc, 0, UINT64_MAX) + heap_size_after_last_full_gc; + double last_full_gc_heap_ratio = (double)heap_size/expected_heap_size; if (heap_size > user_max) { next_sweep_full = 1; gc_count_full_sweep_reason(FULL_SWEEP_REASON_USER_MAX_EXCEEDED); @@ -3304,6 +3310,10 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) next_sweep_full = 1; gc_count_full_sweep_reason(FULL_SWEEP_REASON_LARGE_PROMOTION_RATE); } + else if (last_full_gc_heap_ratio > 1) { + next_sweep_full = 1; + gc_count_full_sweep_reason(FULL_SWEEP_REASON_LARGE_HEAP_GROWTH); + } else { next_sweep_full = 0; } diff --git a/src/gc-stock.h b/src/gc-stock.h index d478ee1366da0..3abd42ea1bfd3 100644 --- a/src/gc-stock.h +++ b/src/gc-stock.h @@ -483,7 +483,8 @@ FORCE_INLINE void gc_big_object_link(bigval_t *sentinel_node, bigval_t *node) JL #define FULL_SWEEP_REASON_FORCED_FULL_SWEEP (1) #define FULL_SWEEP_REASON_USER_MAX_EXCEEDED (2) #define FULL_SWEEP_REASON_LARGE_PROMOTION_RATE (3) -#define FULL_SWEEP_NUM_REASONS (4) +#define FULL_SWEEP_REASON_LARGE_HEAP_GROWTH (4) +#define FULL_SWEEP_NUM_REASONS (5) extern JL_DLLEXPORT uint64_t jl_full_sweep_reasons[FULL_SWEEP_NUM_REASONS]; STATIC_INLINE void gc_count_full_sweep_reason(int reason) JL_NOTSAFEPOINT From 951ca465eb0d2557b4cadfedb5a48b70fd2e7e61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20G=C3=B6ttgens?= Date: Mon, 19 Jan 2026 18:26:42 +0100 Subject: [PATCH 45/83] [release-1.12] Fix JET warnings in `show(::IOBuffer, ::StackFrame)` (#60740) This backports the part of https://github.com/JuliaLang/julia/pull/60645 that is applicable to 1.12. Furthermore, I added a type assertion two lines above the other changes that was taken from https://github.com/JuliaLang/julia/pull/58430. Without this, there are still JET warnings in 1.12 for the above query. cc @DilumAluthge --- base/stacktraces.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/base/stacktraces.jl b/base/stacktraces.jl index 34af576737b33..3c1d5892e138c 100644 --- a/base/stacktraces.jl +++ b/base/stacktraces.jl @@ -273,9 +273,10 @@ function show_spec_linfo(io::IO, frame::StackFrame) if linfo isa Union{MethodInstance, CodeInstance} def = frame_method_or_module(frame) if def isa Module - Base.show_mi(io, linfo, #=from_stackframe=#true) + Base.show_mi(io, linfo::MethodInstance, #=from_stackframe=#true) else - show_spec_sig(io, def, frame_mi(frame).specTypes) + mi = frame_mi(frame)::MethodInstance + show_spec_sig(io, def::Method, mi.specTypes) end else m = linfo::Method From 348463142d6106153c73d0235538c769fdcf1307 Mon Sep 17 00:00:00 2001 From: James Wrigley Date: Mon, 19 Jan 2026 19:50:21 +0100 Subject: [PATCH 46/83] [JuliaSyntax] Bump version for 1.12 (#60641) This is to get https://github.com/JuliaLang/JuliaSyntax.jl/pull/616 in. Part of https://github.com/JuliaLang/julia/pull/60612. --- deps/JuliaSyntax.version | 4 ++-- .../md5 | 1 - .../sha512 | 1 - .../md5 | 1 + .../sha512 | 1 + 5 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 deps/checksums/JuliaSyntax-46723f071d5b2efcb21ca6757788028afb91cc13.tar.gz/md5 delete mode 100644 deps/checksums/JuliaSyntax-46723f071d5b2efcb21ca6757788028afb91cc13.tar.gz/sha512 create mode 100644 deps/checksums/JuliaSyntax-de4d1cd21cf13501c65b91c68c2fd5c9aa704e97.tar.gz/md5 create mode 100644 deps/checksums/JuliaSyntax-de4d1cd21cf13501c65b91c68c2fd5c9aa704e97.tar.gz/sha512 diff --git a/deps/JuliaSyntax.version b/deps/JuliaSyntax.version index 9487754d8a617..4372237a6824f 100644 --- a/deps/JuliaSyntax.version +++ b/deps/JuliaSyntax.version @@ -1,4 +1,4 @@ -JULIASYNTAX_BRANCH = main -JULIASYNTAX_SHA1 = 46723f071d5b2efcb21ca6757788028afb91cc13 +JULIASYNTAX_BRANCH = backports-julialang-1.12 +JULIASYNTAX_SHA1 = de4d1cd21cf13501c65b91c68c2fd5c9aa704e97 JULIASYNTAX_GIT_URL := https://github.com/JuliaLang/JuliaSyntax.jl.git JULIASYNTAX_TAR_URL = https://api.github.com/repos/JuliaLang/JuliaSyntax.jl/tarball/$1 diff --git a/deps/checksums/JuliaSyntax-46723f071d5b2efcb21ca6757788028afb91cc13.tar.gz/md5 b/deps/checksums/JuliaSyntax-46723f071d5b2efcb21ca6757788028afb91cc13.tar.gz/md5 deleted file mode 100644 index ff40f520dfe85..0000000000000 --- a/deps/checksums/JuliaSyntax-46723f071d5b2efcb21ca6757788028afb91cc13.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -2a0921e59edfab54554aa173f091c5b7 diff --git a/deps/checksums/JuliaSyntax-46723f071d5b2efcb21ca6757788028afb91cc13.tar.gz/sha512 b/deps/checksums/JuliaSyntax-46723f071d5b2efcb21ca6757788028afb91cc13.tar.gz/sha512 deleted file mode 100644 index 64e90d0edaba0..0000000000000 --- a/deps/checksums/JuliaSyntax-46723f071d5b2efcb21ca6757788028afb91cc13.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -17050e23216335f6599f009f71e9614a11b6686e455554b1efd287cd8526a7ebece06dc473e34cd50f61bf52085ff72bb4279144a9fdb3a234d3d589a10fddaf diff --git a/deps/checksums/JuliaSyntax-de4d1cd21cf13501c65b91c68c2fd5c9aa704e97.tar.gz/md5 b/deps/checksums/JuliaSyntax-de4d1cd21cf13501c65b91c68c2fd5c9aa704e97.tar.gz/md5 new file mode 100644 index 0000000000000..5daa6f8f8538f --- /dev/null +++ b/deps/checksums/JuliaSyntax-de4d1cd21cf13501c65b91c68c2fd5c9aa704e97.tar.gz/md5 @@ -0,0 +1 @@ +420f41ff75161d7ee4e3a564228de206 diff --git a/deps/checksums/JuliaSyntax-de4d1cd21cf13501c65b91c68c2fd5c9aa704e97.tar.gz/sha512 b/deps/checksums/JuliaSyntax-de4d1cd21cf13501c65b91c68c2fd5c9aa704e97.tar.gz/sha512 new file mode 100644 index 0000000000000..2fa1d2693fd44 --- /dev/null +++ b/deps/checksums/JuliaSyntax-de4d1cd21cf13501c65b91c68c2fd5c9aa704e97.tar.gz/sha512 @@ -0,0 +1 @@ +fbc2cc1b2dd1903c15e33d86a4f1f84807cd7988cd169c62fea58a71af06694deb5d3882a772ab9599ee878bdaa51e069e5a399e565f03b0eb2c99c2b5ec4759 From b8fbf4966c513a9f1b20e0a9b7b163c68706ed69 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Mon, 19 Jan 2026 17:33:37 -0300 Subject: [PATCH 47/83] [1.12] Reland "Add getter for get llvm codeinstances" (#60738) Co-authored-by: William Moses --- src/aotcompile.cpp | 18 ++++++++++++++++++ src/codegen-stubs.c | 4 ++-- src/jl_exported_funcs.inc | 1 + src/julia_internal.h | 3 ++- src/staticdata.c | 2 +- 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index df8a825df3ffe..9a1157afda3e4 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -108,6 +108,24 @@ jl_get_llvm_mis_impl(void *native_code, size_t *num_elements, jl_method_instance } } +extern "C" JL_DLLEXPORT_CODEGEN void +jl_get_llvm_cis_impl(void *native_code, size_t *num_elements, jl_code_instance_t **data) +{ + jl_native_code_desc_t *desc = (jl_native_code_desc_t *)native_code; + auto &map = desc->jl_fvar_map; + + if (data == NULL) { + *num_elements = map.size(); + return; + } + + assert(*num_elements == map.size()); + size_t i = 0; + for (auto &ci : map) { + data[i++] = ci.first; + } +} + extern "C" JL_DLLEXPORT_CODEGEN void jl_get_llvm_gvs_impl(void *native_code, size_t *num_elements, void **data) { diff --git a/src/codegen-stubs.c b/src/codegen-stubs.c index e35fdfddfbab9..7c89ec8d5809c 100644 --- a/src/codegen-stubs.c +++ b/src/codegen-stubs.c @@ -16,8 +16,8 @@ JL_DLLEXPORT void jl_dump_native_fallback(void *native_code, JL_DLLEXPORT void jl_get_llvm_gvs_fallback(void *native_code, arraylist_t *gvs) UNAVAILABLE JL_DLLEXPORT void jl_get_llvm_gvs_globals_fallback(void *native_code, arraylist_t *gvs) UNAVAILABLE JL_DLLEXPORT void jl_get_llvm_external_fns_fallback(void *native_code, arraylist_t *gvs) UNAVAILABLE -JL_DLLEXPORT void jl_get_llvm_mis_fallback(void *native_code, arraylist_t* MIs) UNAVAILABLE - +JL_DLLEXPORT void jl_get_llvm_mis_fallback(void *native_code, size_t *num_elements, jl_method_instance_t **data) UNAVAILABLE +JL_DLLEXPORT void jl_get_llvm_cis_fallback(void *native_code, size_t *num_elements, jl_code_instance_t **data) UNAVAILABLE JL_DLLEXPORT jl_value_t *jl_dump_method_asm_fallback(jl_method_instance_t *linfo, size_t world, char emit_mc, char getwrapper, const char* asm_variant, const char *debuginfo, char binary) UNAVAILABLE JL_DLLEXPORT jl_value_t *jl_dump_function_ir_fallback(jl_llvmf_dump_t *dump, char strip_ir_metadata, char dump_module, const char *debuginfo) UNAVAILABLE diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index 8d2c1d391cb3c..9e3a14aa6cb96 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -526,6 +526,7 @@ YY(jl_get_llvm_gvs_globals) \ YY(jl_get_llvm_external_fns) \ YY(jl_get_llvm_mis) \ + YY(jl_get_llvm_cis) \ YY(jl_dump_function_asm) \ YY(jl_LLVMCreateDisasm) \ YY(jl_LLVMDisasmInstruction) \ diff --git a/src/julia_internal.h b/src/julia_internal.h index a74fcfb7903d3..0d3d45f35501f 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -2065,7 +2065,8 @@ JL_DLLIMPORT void jl_get_function_id(void *native_code, jl_code_instance_t *ncod JL_DLLIMPORT void jl_register_fptrs(uint64_t image_base, const struct _jl_image_fptrs_t *fptrs, jl_method_instance_t **linfos, size_t n); JL_DLLIMPORT void jl_get_llvm_mis(void *native_code, size_t *num_els, - jl_method_instance_t *MIs); + jl_method_instance_t **MIs); +JL_DLLIMPORT void jl_get_llvm_cis(void *native_code, size_t *num_els, jl_code_instance_t **data); JL_DLLIMPORT void jl_init_codegen(void); JL_DLLIMPORT void jl_teardown_codegen(void) JL_NOTSAFEPOINT; JL_DLLIMPORT int jl_getFunctionInfo(jl_frame_t **frames, uintptr_t pointer, int skipC, int noInline) JL_NOTSAFEPOINT; diff --git a/src/staticdata.c b/src/staticdata.c index 466bb349fa4e1..20a265550b612 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -3108,7 +3108,7 @@ static void jl_save_system_image_to_stream(ios_t *f, jl_array_t *mod_array, size_t num_mis; jl_get_llvm_mis(native_functions, &num_mis, NULL); arraylist_grow(&MIs, num_mis); - jl_get_llvm_mis(native_functions, &num_mis, (jl_method_instance_t*)MIs.items); + jl_get_llvm_mis(native_functions, &num_mis, (jl_method_instance_t**)MIs.items); } } if (jl_options.trim) { From 10ccaaf8ad5990f9e4a75404075d6c1e5ad9226c Mon Sep 17 00:00:00 2001 From: William Moses Date: Mon, 19 Jan 2026 21:42:40 -0500 Subject: [PATCH 48/83] [1.12] Reland "Enable getting non-boxed LLVM type from Julia Type" (#60743) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …#59492)" This reverts commit cfcd7d8a327457e4e121457e103989f0185d9dc8. Backport of https://github.com/JuliaLang/julia/pull/60739 --- src/cgutils.cpp | 15 +++++++++++---- src/codegen-stubs.c | 2 ++ src/codegen.cpp | 4 ++-- src/jl_exported_funcs.inc | 1 + 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 65a01c1355f76..cc8ea597516a3 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -628,13 +628,13 @@ static unsigned convert_struct_offset(jl_codectx_t &ctx, Type *lty, unsigned byt static Type *_julia_struct_to_llvm(jl_codegen_params_t *ctx, LLVMContext &ctxt, jl_value_t *jt, bool *isboxed, bool llvmcall=false); -static Type *_julia_type_to_llvm(jl_codegen_params_t *ctx, LLVMContext &ctxt, jl_value_t *jt, bool *isboxed) +static Type *_julia_type_to_llvm(jl_codegen_params_t *ctx, LLVMContext &ctxt, jl_value_t *jt, bool *isboxed, bool no_boxing) { // this function converts a Julia Type into the equivalent LLVM type if (isboxed) *isboxed = false; if (jt == (jl_value_t*)jl_bottom_type || jt == (jl_value_t*)jl_typeofbottom_type || jt == (jl_value_t*)jl_typeofbottom_type->super) return getVoidTy(ctxt); - if (jl_is_concrete_immutable(jt)) { + if (jl_is_concrete_immutable(jt) || no_boxing) { if (jl_datatype_nbits(jt) == 0) return getVoidTy(ctxt); Type *t = _julia_struct_to_llvm(ctx, ctxt, jt, isboxed); @@ -647,13 +647,20 @@ static Type *_julia_type_to_llvm(jl_codegen_params_t *ctx, LLVMContext &ctxt, jl static Type *julia_type_to_llvm(jl_codectx_t &ctx, jl_value_t *jt, bool *isboxed) { - return _julia_type_to_llvm(&ctx.emission_context, ctx.builder.getContext(), jt, isboxed); + return _julia_type_to_llvm(&ctx.emission_context, ctx.builder.getContext(), jt, isboxed, false); } extern "C" JL_DLLEXPORT_CODEGEN Type *jl_type_to_llvm_impl(jl_value_t *jt, LLVMContextRef ctxt, bool *isboxed) { - return _julia_type_to_llvm(NULL, *unwrap(ctxt), jt, isboxed); + return _julia_type_to_llvm(NULL, *unwrap(ctxt), jt, isboxed, false); +} + + +extern "C" JL_DLLEXPORT_CODEGEN +Type *jl_struct_to_llvm_impl(jl_value_t *jt, LLVMContextRef ctxt, bool *isboxed) +{ + return _julia_type_to_llvm(NULL, *unwrap(ctxt), jt, isboxed, true); } diff --git a/src/codegen-stubs.c b/src/codegen-stubs.c index 7c89ec8d5809c..c77c449fa1b3d 100644 --- a/src/codegen-stubs.c +++ b/src/codegen-stubs.c @@ -117,6 +117,8 @@ JL_DLLEXPORT LLVMOrcThreadSafeModuleRef jl_get_llvm_module_fallback(void *native JL_DLLEXPORT void *jl_type_to_llvm_fallback(jl_value_t *jt, LLVMContextRef llvmctxt, bool_t *isboxed) UNAVAILABLE +JL_DLLEXPORT void *jl_struct_to_llvm_fallback(jl_value_t *jt, LLVMContextRef llvmctxt, bool_t *isboxed) UNAVAILABLE + JL_DLLEXPORT jl_value_t *jl_get_libllvm_fallback(void) JL_NOTSAFEPOINT { return jl_nothing; diff --git a/src/codegen.cpp b/src/codegen.cpp index 67d2d134f3ec0..506e99582ad4d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7868,7 +7868,7 @@ static jl_returninfo_t get_specsig_function(jl_codegen_params_t ¶ms, Module } else if (!deserves_retbox(jlrettype)) { bool retboxed; - rt = _julia_type_to_llvm(¶ms, M->getContext(), jlrettype, &retboxed); + rt = _julia_type_to_llvm(¶ms, M->getContext(), jlrettype, &retboxed, /*noboxing*/false); assert(!retboxed); if (rt != getVoidTy(M->getContext()) && deserves_sret(jlrettype, rt)) { auto tracked = CountTrackedPointers(rt, true); @@ -7944,7 +7944,7 @@ static jl_returninfo_t get_specsig_function(jl_codegen_params_t ¶ms, Module if (is_uniquerep_Type(jt)) continue; isboxed = deserves_argbox(jt); - et = isboxed ? T_prjlvalue : _julia_type_to_llvm(¶ms, M->getContext(), jt, nullptr); + et = isboxed ? T_prjlvalue : _julia_type_to_llvm(¶ms, M->getContext(), jt, nullptr, /*noboxing*/false); if (type_is_ghost(et)) continue; } diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index 9e3a14aa6cb96..4f2b5b7cfdd8f 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -544,6 +544,7 @@ YY(jl_dump_fptr_asm) \ YY(jl_emit_native) \ YY(jl_get_function_id) \ + YY(jl_struct_to_llvm) \ YY(jl_type_to_llvm) \ YY(jl_getUnwindInfo) \ YY(jl_get_libllvm) \ From e2ff74f837b3442c1493157b705024e2bd506114 Mon Sep 17 00:00:00 2001 From: William Moses Date: Mon, 19 Jan 2026 21:43:06 -0500 Subject: [PATCH 49/83] =?UTF-8?q?[1.12]=20LateLowerGCFrame:=20More=20relev?= =?UTF-8?q?ant=20diagnostic=20information=20on=20non-=E2=80=A6=20(#60742)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …alloca sret --- src/llvm-late-gc-lowering.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/llvm-late-gc-lowering.cpp b/src/llvm-late-gc-lowering.cpp index 1d262ff7968b0..b5ad4358626dc 100644 --- a/src/llvm-late-gc-lowering.cpp +++ b/src/llvm-late-gc-lowering.cpp @@ -1208,6 +1208,13 @@ State LateLowerGCFrame::LocalScan(Function &F) { auto tracked = CountTrackedPointers(ElT, true); if (tracked.count) { AllocaInst *SRet = dyn_cast((CI->arg_begin()[0])->stripInBoundsOffsets()); + if (!SRet) { + llvm::errs() << "LLVMLateGCLowering: Expected AllocaInst, found" << *(CI->arg_begin()[0])->stripInBoundsOffsets() << "\n"; + llvm::errs() << " + CI: " << *CI << "\n"; + llvm::errs() << " + scope: " << *CI->getFunction() << "\n"; + llvm::errs() << " + callee: " << *CI->getCalledOperand() << "\n"; + llvm_unreachable("LLVMLateGCLowering: Expected AllocaInst"); + } assert(SRet); { if (!(SRet->isStaticAlloca() && isa(ElT) && ElT->getPointerAddressSpace() == AddressSpace::Tracked)) { From ce066ed6df8debdfc2711bae05f7da7fdb20cac5 Mon Sep 17 00:00:00 2001 From: Valentin Churavy Date: Wed, 14 Jan 2026 14:40:12 +0100 Subject: [PATCH 50/83] Preserve the scope across the exception handler (#60647) We store the previous scope in the eh_state and thus hide it from GC. This means we need to manually preserve that scope across the `try ... catch`, instead fo the new scope that we switch to. --------- Co-authored-by: Nathan Daly Co-authored-by: Keno Fischer (cherry picked from commit f22ae77a82ec9adb1182566bc1c2be3a58f0fca2) --- src/codegen.cpp | 9 +++++---- src/gc-interface.h | 7 +++++++ src/interpreter.c | 12 ++++++------ src/rtutils.c | 2 ++ src/task.c | 2 ++ test/scopedvalues.jl | 43 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 65 insertions(+), 10 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 506e99582ad4d..979034b0a1ca5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6172,6 +6172,7 @@ static void emit_stmtpos(jl_codectx_t &ctx, jl_value_t *expr, int ssaval_result) Value *scope_ptr = get_scope_field(ctx); jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe).decorateInst( ctx.builder.CreateAlignedStore(scope_to_restore, scope_ptr, ctx.types().alignof_ptr)); + // NOTE: wb not needed here, due to store to current_task (see jl_gc_wb_current_task) } } else if (head == jl_pop_exception_sym) { @@ -9347,12 +9348,12 @@ static jl_llvm_functions_t Value *scope_ptr = get_scope_field(ctx); LoadInst *current_scope = ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, scope_ptr, ctx.types().alignof_ptr); StoreInst *scope_store = ctx.builder.CreateAlignedStore(scope_boxed, scope_ptr, ctx.types().alignof_ptr); + // NOTE: wb not needed here, due to store to current_task (see jl_gc_wb_current_task) jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe).decorateInst(current_scope); jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_gcframe).decorateInst(scope_store); - // GC preserve the scope, since it is not rooted in the `jl_handler_t *` - // and may be removed from jl_current_task by any nested block and then - // replaced later - Value *scope_token = ctx.builder.CreateCall(prepare_call(gc_preserve_begin_func), {scope_boxed}); + // GC preserve the current_scope, since it is not rooted in the `jl_handler_t *`, + // the newly entered scope is preserved through the current_task. + Value *scope_token = ctx.builder.CreateCall(prepare_call(gc_preserve_begin_func), {current_scope}); ctx.scope_restore[cursor] = std::make_pair(scope_token, current_scope); } } diff --git a/src/gc-interface.h b/src/gc-interface.h index 826e91355b17a..c67b7720e70a5 100644 --- a/src/gc-interface.h +++ b/src/gc-interface.h @@ -241,6 +241,13 @@ STATIC_INLINE void jl_gc_wb(const void *parent, const void *ptr) JL_NOTSAFEPOINT // can be used to annotate that a write barrier would be required were it not for this property // (as opposed to somebody just having forgotten to think about write barriers). STATIC_INLINE void jl_gc_wb_fresh(const void *parent, const void *ptr) JL_NOTSAFEPOINT {} +// As an optimization, the current_task is explicitly added to the remset while it is running. +// Upon deschedule, we conservatively move the write barrier into the young generation. +// This allows the omission of write barriers for all GC roots on the current task stack (JL_GC_PUSH_*), +// as well as the Task's explicit fields (but only for the current task). +// This function is a no-op that can be used to annotate that a write barrier would be required were +// it not for this property (as opposed to somebody just having forgotten to think about write barriers). +STATIC_INLINE void jl_gc_wb_current_task(const void *parent JL_UNUSED, const void *ptr JL_UNUSED) JL_NOTSAFEPOINT {} // Used to annotate that a write barrier would be required, but may be omitted because `ptr` // is known to be an old object. STATIC_INLINE void jl_gc_wb_knownold(const void *parent, const void *ptr) JL_NOTSAFEPOINT {} diff --git a/src/interpreter.c b/src/interpreter.c index a692cadaf9be1..55f8ec9188b19 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -539,12 +539,12 @@ static jl_value_t *eval_body(jl_array_t *stmts, interpreter_state *s, size_t ip, } s->locals[jl_source_nslots(s->src) + ip] = jl_box_ulong(jl_excstack_state(ct)); if (jl_enternode_scope(stmt)) { - jl_value_t *scope = eval_value(jl_enternode_scope(stmt), s); - // GC preserve the scope, since it is not rooted in the `jl_handler_t *` - // and may be removed from jl_current_task by any nested block and then - // replaced later - JL_GC_PUSH1(&scope); - ct->scope = scope; + jl_value_t *old_scope = ct->scope; // Identical to __eh.scope + // GC preserve the old_scope, since it is not rooted in the `jl_handler_t *`, + // the newly entered scope is preserved through the current_task. + JL_GC_PUSH1(&old_scope); + ct->scope = eval_value(jl_enternode_scope(stmt), s); + jl_gc_wb_current_task(ct, ct->scope); if (!jl_setjmp(__eh.eh_ctx, 0)) { ct->eh = &__eh; eval_body(stmts, s, next_ip, toplevel); diff --git a/src/rtutils.c b/src/rtutils.c index 6d4a375017bf2..77ce3c0d4adb0 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -296,6 +296,7 @@ JL_DLLEXPORT void jl_eh_restore_state(jl_task_t *ct, jl_handler_t *eh) ct->eh = eh->prev; ct->gcstack = eh->gcstack; ct->scope = eh->scope; + jl_gc_wb_current_task(ct, ct->scope); small_arraylist_t *locks = &ptls->locks; int unlocks = locks->len > eh->locks_len; if (unlocks) { @@ -335,6 +336,7 @@ JL_DLLEXPORT void jl_eh_restore_state_noexcept(jl_task_t *ct, jl_handler_t *eh) { assert(ct->gcstack == eh->gcstack && "Incorrect GC usage under try catch"); ct->scope = eh->scope; + jl_gc_wb_current_task(ct, ct->scope); ct->eh = eh->prev; ct->ptls->defer_signal = eh->defer_signal; // optional, but certain try-finally (in stream.jl) may be slightly harder to write without this } diff --git a/src/task.c b/src/task.c index 735af58b8fd35..bb86bce48101a 100644 --- a/src/task.c +++ b/src/task.c @@ -1110,6 +1110,7 @@ JL_DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, jl_value_t *completion jl_atomic_store_relaxed(&t->_isexception, 0); // Inherit scope from parent task t->scope = ct->scope; + jl_gc_wb_fresh(t, t->scope); // Fork task-local random state from parent jl_rng_split(t->rngState, ct->rngState); // there is no active exception handler available on this stack yet @@ -1575,6 +1576,7 @@ jl_task_t *jl_init_root_task(jl_ptls_t ptls, void *stack_lo, void *stack_hi) ct->donenotify = jl_nothing; jl_atomic_store_relaxed(&ct->_isexception, 0); ct->scope = jl_nothing; + jl_gc_wb_knownold(ct, ct->scope); ct->eh = NULL; ct->gcstack = NULL; ct->excstack = NULL; diff --git a/test/scopedvalues.jl b/test/scopedvalues.jl index e9b36d80fc2c4..20f709f755915 100644 --- a/test/scopedvalues.jl +++ b/test/scopedvalues.jl @@ -195,3 +195,46 @@ nothrow_scope() push!(ts, 2) end end + +using Base.ScopedValues: ScopedValue, with +@noinline function test_59483() + sv = ScopedValue([]) + ch = Channel{Bool}() + + # Spawn a child task, which inherits the parent's Scope + @noinline function inner_function() + # Block until the parent task has left the scope. + take!(ch) + # Now, per issue 59483, this task's scope is not rooted, except by the task itself. + + # Now switch to an inner scope, leaving the current scope possibly unrooted. + val = with(sv=>Any[2]) do + # Inside this new scope, when we perform GC, the parent scope can be freed. + # The fix for this issue made sure that the first scope in this task remains + # rooted. + GC.gc() + GC.gc() + sv[] + end + @test val == Any[2] + # Finally, we've returned to the original scope, but that could be a dangling + # pointer if the scope itself was freed by the above GCs. So these GCs could crash: + GC.gc() + GC.gc() + end + @noinline function spawn_inner() + # Set a new Scope in the parent task - this is the scope that could be freed. + with(sv=>Any[1]) do + return @async inner_function() + end + end + + # RUN THE TEST: + t = spawn_inner() + # Exit the scope, and let the child task proceed + put!(ch, true) + wait(t) +end +@testset "issue 59483" begin + test_59483() +end From bf91f309fc795308001390e51ea19a252659306d Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Tue, 20 Jan 2026 19:19:35 +0100 Subject: [PATCH 51/83] [1.12] Backport #60718+#60746: Fix and test `jl_method_lookup_by_tt` (#60749) --- src/gf.c | 12 ++++++------ test/core.jl | 26 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/gf.c b/src/gf.c index 47db5474701ac..9dcca5637be09 100644 --- a/src/gf.c +++ b/src/gf.c @@ -1841,7 +1841,7 @@ JL_DLLEXPORT jl_typemap_entry_t *jl_mt_find_cache_entry(jl_methcache_t *mc JL_PR return entry; } -static jl_method_instance_t *jl_mt_assoc_by_type(jl_methcache_t *mc JL_PROPAGATES_ROOT, jl_datatype_t *tt JL_MAYBE_UNROOTED, size_t world) +static jl_method_instance_t *jl_mt_assoc_by_type(jl_methtable_t *mt, jl_methcache_t *mc JL_PROPAGATES_ROOT, jl_datatype_t *tt JL_MAYBE_UNROOTED, size_t world) { jl_typemap_entry_t *entry = jl_mt_find_cache_entry(mc, tt, world); if (entry) @@ -1858,11 +1858,11 @@ static jl_method_instance_t *jl_mt_assoc_by_type(jl_methcache_t *mc JL_PROPAGATE if (!mi) { size_t min_valid = 0; size_t max_valid = ~(size_t)0; - matc = _gf_invoke_lookup((jl_value_t*)tt, jl_method_table, world, 0, &min_valid, &max_valid); + matc = _gf_invoke_lookup((jl_value_t*)tt, mt, world, 0, &min_valid, &max_valid); if (matc) { jl_method_t *m = matc->method; jl_svec_t *env = matc->sparams; - mi = cache_method(jl_method_table, mc, &mc->cache, (jl_value_t*)mc, tt, m, world, min_valid, max_valid, env); + mi = cache_method(mt, mc, &mc->cache, (jl_value_t*)mc, tt, m, world, min_valid, max_valid, env); JL_GC_POP(); return mi; } @@ -3079,7 +3079,7 @@ JL_DLLEXPORT jl_value_t *jl_method_lookup_by_tt(jl_tupletype_t *tt, size_t world mt = (jl_methtable_t*) _mt; } jl_methcache_t *mc = mt->cache; - jl_method_instance_t *mi = jl_mt_assoc_by_type(mc, tt, world); + jl_method_instance_t *mi = jl_mt_assoc_by_type(mt, mc, tt, world); if (!mi) return jl_nothing; return (jl_value_t*) mi; @@ -3094,7 +3094,7 @@ JL_DLLEXPORT jl_method_instance_t *jl_method_lookup(jl_value_t **args, size_t na if (entry) return entry->func.linfo; jl_tupletype_t *tt = arg_type_tuple(args[0], &args[1], nargs); - return jl_mt_assoc_by_type(mc, tt, world); + return jl_mt_assoc_by_type(jl_method_table, mc, tt, world); } // return a Vector{Any} of svecs, each describing a method match: @@ -4169,7 +4169,7 @@ STATIC_INLINE jl_method_instance_t *jl_lookup_generic_(jl_value_t *F, jl_value_t assert(tt); // cache miss case jl_methcache_t *mc = jl_method_table->cache; - mfunc = jl_mt_assoc_by_type(mc, tt, world); + mfunc = jl_mt_assoc_by_type(jl_method_table, mc, tt, world); if (jl_options.malloc_log) jl_gc_sync_total_bytes(last_alloc); // discard allocation count from compilation if (mfunc == NULL) { diff --git a/test/core.jl b/test/core.jl index d18f7fe8136b6..d85a4f3c2eb74 100644 --- a/test/core.jl +++ b/test/core.jl @@ -8422,6 +8422,32 @@ let ms = Base._methods_by_ftype(Tuple{typeof(sin), Int}, OverlayModule.mt, 1, Ba @test isempty(ms) end +# fresh module to ensure uncached methods +module OverlayMTTest + using Base.Experimental: @MethodTable, @overlay + @MethodTable(mt) + + function overlay_only end + @overlay mt overlay_only(x::Int) = x * 2 +end + +# #60702 & #60716: Overlay methods must be found without prior cache population +let world = Base.get_world_counter() + mi = Base.method_instance(OverlayMTTest.overlay_only, Tuple{Int}; + world, method_table=OverlayMTTest.mt) + @test mi isa Core.MethodInstance + @test mi.def.module === OverlayMTTest +end + +# #60712: Global-only methods must NOT be found via custom MT +let + @eval global_only_func(x::Int) = x + 1 + world = Base.get_world_counter() + mi = Base.method_instance(global_only_func, Tuple{Int}; + world, method_table=OverlayMTTest.mt) + @test mi === nothing +end + # precompilation let load_path = mktempdir() depot_path = mkdepottempdir() From 13b377ad7188b045bc90a394da07feafa97b0845 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Tue, 20 Jan 2026 17:09:31 -0300 Subject: [PATCH 52/83] [1.12] Don't skip CIs from external absints (#60741) Should fix one of the GPUCompiler caching issues --------- Co-authored-by: Valentin Churavy Co-authored-by: Dilum Aluthge --- src/staticdata_utils.c | 2 +- test/precompile_absint1.jl | 30 +++++++++++------------------- test/precompile_absint2.jl | 37 +++++++++++++------------------------ test/precompile_utils.jl | 11 +++++++++++ 4 files changed, 36 insertions(+), 44 deletions(-) diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index 1d8ed0e19b04b..0dc64d27a57a9 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -314,7 +314,7 @@ static jl_array_t *queue_external_cis(jl_array_t *list, jl_query_cache *query_ca assert(jl_is_code_instance(ci)); jl_method_instance_t *mi = jl_get_ci_mi(ci); jl_method_t *m = mi->def.method; - if (ci->owner == jl_nothing && jl_atomic_load_relaxed(&ci->inferred) && jl_is_method(m) && jl_object_in_image((jl_value_t*)m->module)) { + if (jl_atomic_load_relaxed(&ci->inferred) && jl_is_method(m) && jl_object_in_image((jl_value_t*)m->module)) { int found = has_backedge_to_worklist(mi, &visited, &stack, query_cache); assert(found == 0 || found == 1 || found == 2); assert(stack.len == 0); diff --git a/test/precompile_absint1.jl b/test/precompile_absint1.jl index 98078ebf41098..000ba116bae95 100644 --- a/test/precompile_absint1.jl +++ b/test/precompile_absint1.jl @@ -43,43 +43,35 @@ precompile_test_harness() do load_path let m = only(methods(TestAbsIntPrecompile1.basic_callee)) mi = only(Base.specializations(m)) ci = mi.cache - @test_broken isdefined(ci, :next) + ci = check_presence(mi, nothing) + @test ci !== nothing @test ci.owner === nothing @test ci.max_world == typemax(UInt) @test Base.module_build_id(TestAbsIntPrecompile1) == Base.object_build_id(ci) - @test_skip begin - ci = ci.next - @test !isdefined(ci, :next) + ci = check_presence(mi, cache_owner) + @test ci !== nothing @test ci.owner === cache_owner @test ci.max_world == typemax(UInt) @test Base.module_build_id(TestAbsIntPrecompile1) == Base.object_build_id(ci) - end end let m = only(methods(sum, (Vector{Float64},))) - found = false for mi in Base.specializations(m) if mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(sum),Vector{Float64}} - ci = mi.cache - @test_broken isdefined(ci, :next) - @test_broken ci.owner === cache_owner - @test_skip begin - @test ci.max_world == typemax(UInt) - @test Base.module_build_id(TestAbsIntPrecompile1) == - Base.object_build_id(ci) - ci = ci.next - end - @test !isdefined(ci, :next) + ci = check_presence(mi, nothing) + @test ci !== nothing @test ci.owner === nothing @test ci.max_world == typemax(UInt) + @test Base.module_build_id(TestAbsIntPrecompile1) == Base.object_build_id(ci) + ci = check_presence(mi, cache_owner) + @test ci !== nothing + @test ci.owner === cache_owner + @test ci.max_world == typemax(UInt) @test Base.module_build_id(TestAbsIntPrecompile1) == Base.object_build_id(ci) - found = true - break end end - @test found end end end diff --git a/test/precompile_absint2.jl b/test/precompile_absint2.jl index 4aa84e0992f7c..5b0ba32a8df82 100644 --- a/test/precompile_absint2.jl +++ b/test/precompile_absint2.jl @@ -62,44 +62,33 @@ precompile_test_harness() do load_path TestAbsIntPrecompile2.Custom.PrecompileInterpreter()) let m = only(methods(TestAbsIntPrecompile2.basic_callee)) mi = only(Base.specializations(m)) - ci = mi.cache - @test_broken isdefined(ci, :next) + ci = check_presence(mi, nothing) + @test ci !== nothing @test ci.owner === nothing @test ci.max_world == typemax(UInt) @test Base.module_build_id(TestAbsIntPrecompile2) == Base.object_build_id(ci) - @test_skip begin - ci = ci.next - @test !isdefined(ci, :next) + ci = check_presence(mi, cache_owner) + @test ci !== nothing @test ci.owner === cache_owner @test ci.max_world == typemax(UInt) - @test Base.module_build_id(TestAbsIntPrecompile2) == - Base.object_build_id(ci) - end + @test Base.module_build_id(TestAbsIntPrecompile2) == Base.object_build_id(ci) end let m = only(methods(sum, (Vector{Float64},))) - found = false for mi = Base.specializations(m) if mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(sum),Vector{Float64}} - ci = mi.cache - @test_broken isdefined(ci, :next) - @test_broken ci.owner === cache_owner - @test_skip begin - @test ci.max_world == typemax(UInt) - @test Base.module_build_id(TestAbsIntPrecompile2) == - Base.object_build_id(ci) - ci = ci.next - end - @test !isdefined(ci, :next) + ci = check_presence(mi, nothing) + @test ci !== nothing @test ci.owner === nothing @test ci.max_world == typemax(UInt) - @test Base.module_build_id(TestAbsIntPrecompile2) == - Base.object_build_id(ci) - found = true - break + @test Base.module_build_id(TestAbsIntPrecompile2) == Base.object_build_id(ci) + ci = check_presence(mi, cache_owner) + @test ci !== nothing + @test ci.owner === cache_owner + @test ci.max_world == typemax(UInt) + @test Base.module_build_id(TestAbsIntPrecompile2) == Base.object_build_id(ci) end end - @test found end end end diff --git a/test/precompile_utils.jl b/test/precompile_utils.jl index c9a7c98d262e0..685161e98840f 100644 --- a/test/precompile_utils.jl +++ b/test/precompile_utils.jl @@ -29,3 +29,14 @@ let original_depot_path = copy(Base.DEPOT_PATH) append!(Base.LOAD_PATH, original_load_path) end end + +function check_presence(mi, token) + ci = isdefined(mi, :cache) ? mi.cache : nothing + while ci !== nothing + if ci.owner === token && ci.max_world == typemax(UInt) + return ci + end + ci = isdefined(ci, :next) ? ci.next : nothing + end + return nothing +end From 0d0c031a46f429570034219c5eb9e9014155d7ae Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Wed, 14 Jan 2026 15:49:45 -0500 Subject: [PATCH 53/83] codegen: Use `emit_static_roots` for "allroots" case (#60656) The way this ABI optimization is implemented is a bit awkward, since it means that either the "bytes" have to start acting like "pointers" or vice-versa. This adds some minimal plumbing to make sure that we label these as roots appropriately (and zero-init them). --- src/codegen.cpp | 7 ++++++- src/jitlayers.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 979034b0a1ca5..ce3f10bbae9b5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5020,7 +5020,11 @@ static jl_cgval_t emit_call_specfun_other(jl_codectx_t &ctx, bool is_opaque_clos AllocaInst *result = nullptr; if (returninfo.cc == jl_returninfo_t::SRet || returninfo.cc == jl_returninfo_t::Union) { - result = emit_static_alloca(ctx, returninfo.union_bytes, Align(returninfo.union_align)); + if (returninfo.all_roots) { + result = emit_static_roots(ctx, returninfo.union_bytes / sizeof(void *)); + } else { + result = emit_static_alloca(ctx, returninfo.union_bytes, Align(returninfo.union_align)); + } setName(ctx.emission_context, result, "sret_box"); argvals[idx] = result; idx++; @@ -7881,6 +7885,7 @@ static jl_returninfo_t get_specsig_function(jl_codegen_params_t ¶ms, Module props.cc = jl_returninfo_t::SRet; props.union_bytes = jl_datatype_size(jlrettype); props.union_align = props.union_minalign = julia_alignment(jlrettype); + props.all_roots = tracked.all; // sret is always passed from alloca assert(M); fsig.push_back(rt->getPointerTo(M->getDataLayout().getAllocaAddrSpace())); diff --git a/src/jitlayers.h b/src/jitlayers.h index 070bf576ffd35..7975d4c4163a7 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -203,6 +203,7 @@ struct jl_returninfo_t { size_t union_align; size_t union_minalign; unsigned return_roots; + bool all_roots; }; struct jl_codegen_call_target_t { From b8e84ae2b53fc6d7038aea587a0e81e2c8e23370 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Sat, 24 Jan 2026 11:15:40 +0100 Subject: [PATCH 54/83] [1.12] Fix `codeinfo_for_const` missing `nargs` and `isva` fields (#60787) Backport a fix from #59413 to unbreak `Compiler.inflate_ir!` with const-return IR. --- Compiler/src/typeinfer.jl | 2 ++ Compiler/test/ssair.jl | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/Compiler/src/typeinfer.jl b/Compiler/src/typeinfer.jl index 746b32c22506c..060072e834f2c 100644 --- a/Compiler/src/typeinfer.jl +++ b/Compiler/src/typeinfer.jl @@ -1052,6 +1052,8 @@ function codeinfo_for_const(interp::AbstractInterpreter, mi::MethodInstance, @no tree.ssaflags = [IR_FLAG_NULL] tree.rettype = Core.Typeof(val) tree.edges = Core.svec() + tree.nargs = UInt(nargs) + tree.isva = method.isva set_inlineable!(tree, true) tree.parent = mi return tree diff --git a/Compiler/test/ssair.jl b/Compiler/test/ssair.jl index 80faac97d83a4..f7ceda07601e2 100644 --- a/Compiler/test/ssair.jl +++ b/Compiler/test/ssair.jl @@ -838,3 +838,15 @@ end let ir = Base.code_ircode(_worker_task57153, (), optimize_until="CC: COMPACT_2")[1].first @test findfirst(x->x==0, ir.cfg.blocks[1].preds) !== nothing end + +# codeinfo_for_const should set nargs and isva +let + _const_return_func(@nospecialize(x)) = 42 + mi = Compiler.specialize_method(only(methods(_const_return_func)), Tuple{typeof(_const_return_func), Int}, Core.svec()) + ci = Compiler.codeinfo_for_const(Compiler.NativeInterpreter(), mi, 42) + @test ci.nargs == 2 + @test ci.isva == false + # inflate_ir! should succeed now that nargs/isva are set + ir = Compiler.inflate_ir!(ci, mi) + @test ir isa Compiler.IRCode +end From 3d40701b4f020162c49284c911ca23b62765e586 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Wed, 21 Jan 2026 02:44:19 -0300 Subject: [PATCH 55/83] llvm: Fix alloca alignment and type selection in AllocOpt (#60699) Inherit alignment from the original GC allocation with JL_SMALL_BYTE_ALIGNMENT as the minimum. Use alignment-sized integer chunks for the alloca type (matching emit_static_alloca) so SROA splits allocations into aligned pieces for better performance and vectorization. Also adds the missing setAlignment call in splitOnStack. Co-Authored-By: Claude Opus 4.5 --------- Co-authored-by: Claude Opus 4.5 (cherry picked from commit 54fde7e012e6883a5bc9acd964593c8b9c9b5c74) --- src/codegen.cpp | 8 ++-- src/llvm-alloc-opt.cpp | 37 +++++++++------ .../alloc-opt-gcframe-addrspaces.ll | 2 +- test/llvmpasses/alloc-opt-gcframe.ll | 9 ++-- test/llvmpasses/alloc-opt-pass.ll | 45 ++++++++++++++++--- 5 files changed, 72 insertions(+), 29 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index ce3f10bbae9b5..816a4d24583a8 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2163,9 +2163,11 @@ static AllocaInst *emit_static_alloca(jl_codectx_t &ctx, unsigned nb, Align alig // if it cannot find something better to do, which is terrible for performance. // However, if we emit this with an element size equal to the alignment, it will instead split it into aligned chunks // which is great for performance and vectorization. - if (alignTo(nb, align) == align.value()) // don't bother with making an array of length 1 - return emit_static_alloca(ctx, ctx.builder.getIntNTy(align.value() * 8), align); - return emit_static_alloca(ctx, ArrayType::get(ctx.builder.getIntNTy(align.value() * 8), alignTo(nb, align) / align.value()), align); + // Cap element size at 64 bits since not all backends support larger integers. + unsigned elsize = std::min(align.value(), (uint64_t)8); + if (alignTo(nb, elsize) == elsize) // don't bother with making an array of length 1 + return emit_static_alloca(ctx, ctx.builder.getIntNTy(elsize * 8), align); + return emit_static_alloca(ctx, ArrayType::get(ctx.builder.getIntNTy(elsize * 8), alignTo(nb, elsize) / elsize), align); } static AllocaInst *emit_static_roots(jl_codectx_t &ctx, unsigned nroots) diff --git a/src/llvm-alloc-opt.cpp b/src/llvm-alloc-opt.cpp index 7005d4329c9fc..97e881296d1be 100644 --- a/src/llvm-alloc-opt.cpp +++ b/src/llvm-alloc-opt.cpp @@ -662,11 +662,8 @@ void Optimizer::moveToStack(CallInst *orig_inst, size_t sz, bool has_ref, AllocF // The allocation does not escape or get used in a phi node so none of the derived // SSA from it are live when we run the allocation again. // It is now safe to promote the allocation to an entry block alloca. - size_t align = 1; - // TODO: This is overly conservative. May want to instead pass this as a - // parameter to the allocation function directly. - if (sz > 1) - align = MinAlign(JL_SMALL_BYTE_ALIGNMENT, NextPowerOf2(sz)); + // Inherit alignment from the original allocation, with GC alignment as minimum. + Align align(std::max((unsigned)orig_inst->getRetAlign().valueOrOne().value(), (unsigned)JL_SMALL_BYTE_ALIGNMENT)); // No debug info for prolog instructions IRBuilder<> prolog_builder(&F.getEntryBlock().front()); AllocaInst *buff; @@ -682,17 +679,21 @@ void Optimizer::moveToStack(CallInst *orig_inst, size_t sz, bool has_ref, AllocF 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)); + buff->setAlignment(align); ptr = cast(buff); } else { + // Use alignment-sized chunks so SROA splits the alloca into aligned pieces + // which is better for performance and vectorization (see emit_static_alloca). + // Cap element size at 64 bits since not all backends support larger integers. Type *buffty; - if (pass.DL->isLegalInteger(sz * 8)) - buffty = Type::getIntNTy(pass.getLLVMContext(), sz * 8); + unsigned elsize = std::min(align.value(), (uint64_t)8); + if (alignTo(sz, elsize) == elsize) + buffty = Type::getIntNTy(pass.getLLVMContext(), elsize * 8); else - buffty = ArrayType::get(Type::getInt8Ty(pass.getLLVMContext()), sz); + buffty = ArrayType::get(Type::getIntNTy(pass.getLLVMContext(), elsize * 8), alignTo(sz, elsize) / elsize); buff = prolog_builder.CreateAlloca(buffty); - buff->setAlignment(Align(align)); + buff->setAlignment(align); ptr = cast(buff); } insertLifetime(ptr, ConstantInt::get(Type::getInt64Ty(prolog_builder.getContext()), sz), orig_inst); @@ -959,6 +960,8 @@ void Optimizer::splitOnStack(CallInst *orig_inst) uint32_t size; }; SmallVector slots; + // Inherit alignment from the original allocation, with GC alignment as minimum. + Align align(std::max((unsigned)orig_inst->getRetAlign().valueOrOne().value(), (unsigned)JL_SMALL_BYTE_ALIGNMENT)); for (auto memop: use_info.memops) { auto offset = memop.first; auto &field = memop.second; @@ -974,12 +977,18 @@ void Optimizer::splitOnStack(CallInst *orig_inst) else if (field.elty && !field.multiloc) { allocty = field.elty; } - else if (pass.DL->isLegalInteger(field.size * 8)) { - allocty = Type::getIntNTy(pass.getLLVMContext(), field.size * 8); - } else { - allocty = ArrayType::get(Type::getInt8Ty(pass.getLLVMContext()), field.size); + else { + // Use alignment-sized chunks so SROA splits the alloca into aligned pieces + // which is better for performance and vectorization (see emit_static_alloca). + // Cap element size at 64 bits since not all backends support larger integers. + unsigned elsize = std::min(align.value(), (uint64_t)8); + if (alignTo(field.size, elsize) == elsize) + allocty = Type::getIntNTy(pass.getLLVMContext(), elsize * 8); + else + allocty = ArrayType::get(Type::getIntNTy(pass.getLLVMContext(), elsize * 8), alignTo(field.size, elsize) / elsize); } slot.slot = prolog_builder.CreateAlloca(allocty); + slot.slot->setAlignment(align); IRBuilder<> builder(orig_inst); insertLifetime(slot.slot, ConstantInt::get(Type::getInt64Ty(prolog_builder.getContext()), field.size), orig_inst); initializeAlloca(builder, slot.slot, use_info.allockind); diff --git a/test/llvmpasses/alloc-opt-gcframe-addrspaces.ll b/test/llvmpasses/alloc-opt-gcframe-addrspaces.ll index b96c9385e38eb..c66cb815ea8b9 100644 --- a/test/llvmpasses/alloc-opt-gcframe-addrspaces.ll +++ b/test/llvmpasses/alloc-opt-gcframe-addrspaces.ll @@ -16,7 +16,7 @@ declare {}* @julia.pointer_from_objref({} addrspace(11)*) ; CHECK-LABEL: @non_zero_addrspace -; OPAQUE: %var1 = alloca i32, align 8, addrspace(5) +; OPAQUE: %var1 = alloca i64, align 16, addrspace(5) ; OPAQUE: %1 = addrspacecast ptr addrspace(5) %var1 to ptr ; OPAQUE: call void @llvm.lifetime.start.p5(i64 4, ptr addrspace(5) %var1) diff --git a/test/llvmpasses/alloc-opt-gcframe.ll b/test/llvmpasses/alloc-opt-gcframe.ll index f53a4d5c01df7..44714b702d7bc 100644 --- a/test/llvmpasses/alloc-opt-gcframe.ll +++ b/test/llvmpasses/alloc-opt-gcframe.ll @@ -25,7 +25,8 @@ define {} addrspace(10)* @return_obj() { ; CHECK-LABEL: }{{$}} ; CHECK-LABEL: @return_load -; CHECK: alloca i64 +; When the element type is known (i64), splitOnStack preserves it +; CHECK: alloca i64, align 16 ; CHECK-NOT: @julia.gc_alloc_obj ; CHECK-NOT: @jl_gc_small_alloc ; OPAQUE: call void @llvm.lifetime.start{{.*}}(i64 8, ptr @@ -62,7 +63,7 @@ define void @ccall_obj(i8* %fptr) { ; CHECK-LABEL: }{{$}} ; CHECK-LABEL: @ccall_ptr -; CHECK: alloca i64 +; CHECK: alloca i64, align 16 ; OPAQUE: call ptr @julia.get_pgcstack() ; CHECK-NOT: @julia.gc_alloc_obj ; CHECK-NOT: @jl_gc_small_alloc @@ -105,7 +106,7 @@ define void @ccall_unknown_bundle(i8* %fptr) { ; CHECK-LABEL: }{{$}} ; CHECK-LABEL: @lifetime_branches -; CHECK: alloca i64 +; CHECK: alloca i64, align 16 ; OPAQUE: call ptr @julia.get_pgcstack() ; CHECK: L1: ; CHECK-NEXT: call void @llvm.lifetime.start{{.*}}(i64 8, @@ -166,7 +167,7 @@ define void @object_field({} addrspace(10)* %field) { ; CHECK-LABEL: }{{$}} ; CHECK-LABEL: @memcpy_opt -; CHECK: alloca [16 x i8], align 16 +; CHECK: alloca [2 x i64], align 16 ; OPAQUE: call ptr @julia.get_pgcstack() ; CHECK-NOT: @julia.gc_alloc_obj ; CHECK-NOT: @jl_gc_small_alloc diff --git a/test/llvmpasses/alloc-opt-pass.ll b/test/llvmpasses/alloc-opt-pass.ll index 83f2118412cc1..ad79baafd19dd 100644 --- a/test/llvmpasses/alloc-opt-pass.ll +++ b/test/llvmpasses/alloc-opt-pass.ll @@ -79,8 +79,9 @@ declare ptr addrspace(10) @external_function2() ; CHECK-LABEL: @legal_int_types -; CHECK: alloca [12 x i8] -; CHECK-NOT: alloca i96 +; Test that allocations use i64 chunks (capped at 64 bits for backend compatibility) +; A 12-byte allocation rounds up to 16 bytes, giving [2 x i64] +; CHECK: alloca [2 x i64], align 16 ; CHECK: call void @llvm.memset.p0.i64(ptr align 16 %var1, ; CHECK: ret void define void @legal_int_types() { @@ -151,11 +152,10 @@ define void @lifetime_no_preserve_end(ptr noalias nocapture noundef nonnull sret ; CHECK-LABEL: @initializers -; CHECK: alloca [1 x i8] -; CHECK-DAG: alloca [2 x i8] -; CHECK-DAG: alloca [3 x i8] -; CHECK-DAG: call void @llvm.memset.p0.i64(ptr align 1 %var1, -; CHECK-DAG: call void @llvm.memset.p0.i64(ptr align 4 %var7, +; Small allocations (1, 2, 3 bytes) all round up to 8 bytes, giving i64 +; CHECK-DAG: alloca i64, align 16 +; CHECK-DAG: call void @llvm.memset.p0.i64(ptr align 16 %var1, +; CHECK-DAG: call void @llvm.memset.p0.i64(ptr align 16 %var7, ; CHECK: ret void define void @initializers() { %pgcstack = call ptr @julia.get_pgcstack() @@ -268,6 +268,37 @@ define swiftcc i64 @"atomicrmw"(ptr nonnull swiftself %0) #0 { ret i64 %19 } +; Test that higher alignment from the original allocation is inherited +; 8 bytes with 32-byte alignment uses i64 (element size capped at 64 bits) +; CHECK-LABEL: @align_inherit +; CHECK: alloca i64, align 32 +; CHECK: ret void +define void @align_inherit() { + %pgcstack = call ptr @julia.get_pgcstack() + %ptls = call ptr @julia.ptls_states() + %ptls_i8 = bitcast ptr %ptls to ptr + %var1 = call align 32 ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 8, ptr addrspace(10) @tag) + %var2 = addrspacecast ptr addrspace(10) %var1 to ptr addrspace(11) + %var3 = call ptr @julia.pointer_from_objref(ptr addrspace(11) %var2) + ret void +} +; CHECK-LABEL: }{{$}} + +; Test that 8-byte allocation uses i64 with GC alignment +; CHECK-LABEL: @legal_int_i64 +; CHECK: alloca i64, align 16 +; CHECK: ret void +define void @legal_int_i64() { + %pgcstack = call ptr @julia.get_pgcstack() + %ptls = call ptr @julia.ptls_states() + %ptls_i8 = bitcast ptr %ptls to ptr + %var1 = call ptr addrspace(10) @julia.gc_alloc_obj(ptr %ptls_i8, i64 8, ptr addrspace(10) @tag) + %var2 = addrspacecast ptr addrspace(10) %var1 to ptr addrspace(11) + %var3 = call ptr @julia.pointer_from_objref(ptr addrspace(11) %var2) + ret void +} +; CHECK-LABEL: }{{$}} + declare ptr @julia.ptls_states() declare ptr @julia.pointer_from_objref(ptr addrspace(11)) From 0f21d93eaa6ad75fb4be985b9f85c740be8755e9 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sat, 24 Jan 2026 10:32:55 -0500 Subject: [PATCH 56/83] bindings: Define behavior of `using` an ambiguous binding (#60804) We were missing handling for the case where the binding that we're using is ambiguous. There are two possible behaviors: 1. The ambiguous binding gets ignored for the purpose of resolution 2. The ambiguity poisons and the imported binding is also ambiguous Current behavior between these two depends on resolution order (which is bad and part of what the assert was complaining about). This decides that case #2 is the correct behavior and fixes #60659. (cherry picked from commit 0f275e3e8b43bed4062c33ddb615ae9aececd4c3) --- src/module.c | 5 ++++- test/core.jl | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/module.c b/src/module.c index 60d2652ddfaaa..546a8d3e60fb8 100644 --- a/src/module.c +++ b/src/module.c @@ -104,7 +104,6 @@ static void update_implicit_resolution(struct implicit_search_resolution *to_upd return; } if (to_update->ultimate_kind == PARTITION_KIND_GUARD) { - assert(resolution.binding_or_const); to_update->ultimate_kind = resolution.ultimate_kind; to_update->binding_or_const = resolution.binding_or_const; to_update->debug_only_import_from = resolution.debug_only_import_from; @@ -310,6 +309,10 @@ struct implicit_search_resolution jl_resolve_implicit_import(jl_binding_t *b, mo imp_resolution.binding_or_const = tempbpart->restriction; imp_resolution.debug_only_ultimate_binding = tempb; imp_resolution.ultimate_kind = PARTITION_KIND_IMPLICIT_CONST; + } else if (kind == PARTITION_KIND_FAILED) { + imp_resolution.binding_or_const = NULL; + imp_resolution.debug_only_ultimate_binding = tempb; + imp_resolution.ultimate_kind = PARTITION_KIND_FAILED; } } imp_resolution.debug_only_import_from = imp; diff --git a/test/core.jl b/test/core.jl index d85a4f3c2eb74..dd2dfd86b9619 100644 --- a/test/core.jl +++ b/test/core.jl @@ -8631,3 +8631,17 @@ primitive type ByteString58434 (18 * 8) end @test Base.datatype_isbitsegal(Tuple{ByteString58434}) == false @test Base.datatype_haspadding(Tuple{ByteString58434}) == (length(Base.padding(Tuple{ByteString58434})) > 0) + +# #60659 - Behavior of using'd ambiguous bindings +module AmbiguousUsing60659 + using Test + module A + export X + module B; struct X; end; export X; end + module C; struct X; end; export X; end + using .B, .C + end + module D; struct X; end; export X; end + using .D, .A + @test_throws UndefVarError X +end From 164ac88aef0d33caf1755c9edef110e62b92edac Mon Sep 17 00:00:00 2001 From: Sam Schweigel Date: Tue, 20 Jan 2026 08:15:37 -0800 Subject: [PATCH 57/83] Temporarily reintroduce a global type inference lock (#60689) (cherry picked from commit 23a98ffd193a0946636976bcd92af8f69853f8b6) --- src/gf.c | 8 ++++++-- src/init.c | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/gf.c b/src/gf.c index 9dcca5637be09..2c5abf7343d09 100644 --- a/src/gf.c +++ b/src/gf.c @@ -399,6 +399,8 @@ static jl_code_instance_t *jl_method_inferred_with_abi(jl_method_instance_t *mi return NULL; } +jl_mutex_t jl_typeinf_lock; + // run type inference on lambda "mi" for given argument types. // returns the inferred source, and may cache the result in mi // if successful, also updates the mi argument to describe the validity of this src @@ -427,6 +429,7 @@ jl_code_instance_t *jl_type_infer(jl_method_instance_t *mi, size_t world, uint8_ return NULL; JL_TIMING(INFERENCE, INFERENCE); jl_value_t **fargs; + JL_GC_PUSH1(&ci); JL_GC_PUSHARGS(fargs, 5); fargs[0] = (jl_value_t*)jl_typeinf_func; fargs[1] = (jl_value_t*)mi; @@ -458,6 +461,7 @@ jl_code_instance_t *jl_type_infer(jl_method_instance_t *mi, size_t world, uint8_ // increase that limit, we'll need to // allocate another bit for the counter. ct->reentrant_timing += 0b10; + JL_LOCK(&jl_typeinf_lock); JL_TRY { ci = (jl_code_instance_t*)jl_apply(fargs, 5); } @@ -481,6 +485,7 @@ jl_code_instance_t *jl_type_infer(jl_method_instance_t *mi, size_t world, uint8_ abort(); #endif } + JL_UNLOCK(&jl_typeinf_lock); ct->world_age = last_age; ct->reentrant_timing -= 0b10; ct->ptls->in_pure_callback = last_pure; @@ -495,12 +500,11 @@ jl_code_instance_t *jl_type_infer(jl_method_instance_t *mi, size_t world, uint8_ // Record inference entrance backtrace if enabled if (ci) { - JL_GC_PUSH1(&ci); jl_push_inference_entrance_backtraces((jl_value_t*)ci); - JL_GC_POP(); } JL_GC_POP(); + JL_GC_POP(); #endif return ci; diff --git a/src/init.c b/src/init.c index e11b360b5d378..f86435b3b9035 100644 --- a/src/init.c +++ b/src/init.c @@ -552,6 +552,7 @@ extern jl_mutex_t precomp_statement_out_lock; extern jl_mutex_t newly_inferred_mutex; extern jl_mutex_t global_roots_lock; extern jl_mutex_t profile_show_peek_cond_lock; +extern jl_mutex_t jl_typeinf_lock; static void restore_fp_env(void) { @@ -661,6 +662,7 @@ static void init_global_mutexes(void) { JL_MUTEX_INIT(&global_roots_lock, "global_roots_lock"); JL_MUTEX_INIT(&typecache_lock, "typecache_lock"); JL_MUTEX_INIT(&profile_show_peek_cond_lock, "profile_show_peek_cond_lock"); + JL_MUTEX_INIT(&jl_typeinf_lock, "jl_typeinf_lock"); } JL_DLLEXPORT void jl_init_(jl_image_buf_t sysimage) From a1391e5af89b1500ad0a81e061b18c8b06a7eaa7 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Wed, 28 Jan 2026 14:58:13 +0100 Subject: [PATCH 58/83] bump Pkg to latest release-1.12 --- stdlib/Pkg.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 853940e299a8e..56f673f582df6 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = release-1.12 -PKG_SHA1 = b322a8ff786472d680a972e57575b4586fefe018 +PKG_SHA1 = 1c1c173d35be3eb478054fb0229b0b1b6aa040cf PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 From 422f456051886227b11b6a65faecadd99b79fb71 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 27 Jan 2026 22:43:12 +0100 Subject: [PATCH 59/83] Make `jl_reinit_foreign_type` idempotent even with asserts (#60827) That is, if it is called twice (e.g. because precompilation is disabled) with identical arguments, then this should not trigger an assertion. This should resolve https://github.com/oscar-system/GAP.jl/issues/1314 (cherry picked from commit 1708d99d98e1d0e5b3b277f74b6a10f2f675387d) --- src/datatype.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/datatype.c b/src/datatype.c index 4cf2c6d780bbd..447586135cdc7 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -1040,10 +1040,14 @@ JL_DLLEXPORT int jl_reinit_foreign_type(jl_datatype_t *dt, const jl_datatype_layout_t *layout = dt->layout; jl_fielddescdyn_t * desc = (jl_fielddescdyn_t *) ((char *)layout + sizeof(*layout)); - assert(!desc->markfunc); - assert(!desc->sweepfunc); - desc->markfunc = markfunc; - desc->sweepfunc = sweepfunc; + if (desc->markfunc != markfunc) { + assert(!desc->markfunc); + desc->markfunc = markfunc; + } + if (desc->sweepfunc != sweepfunc) { + assert(!desc->sweepfunc); + desc->sweepfunc = sweepfunc; + } return 1; } From fc453392ecd42b478cd156514576d4f44328adb1 Mon Sep 17 00:00:00 2001 From: Dilum Aluthge Date: Wed, 28 Jan 2026 21:38:33 -0500 Subject: [PATCH 60/83] `deps/checksums`: Remove old Pkg checksums, and add new Pkg checksums --- .../Pkg-1c1c173d35be3eb478054fb0229b0b1b6aa040cf.tar.gz/md5 | 1 + .../Pkg-1c1c173d35be3eb478054fb0229b0b1b6aa040cf.tar.gz/sha512 | 1 + .../Pkg-b322a8ff786472d680a972e57575b4586fefe018.tar.gz/md5 | 1 - .../Pkg-b322a8ff786472d680a972e57575b4586fefe018.tar.gz/sha512 | 1 - 4 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 deps/checksums/Pkg-1c1c173d35be3eb478054fb0229b0b1b6aa040cf.tar.gz/md5 create mode 100644 deps/checksums/Pkg-1c1c173d35be3eb478054fb0229b0b1b6aa040cf.tar.gz/sha512 delete mode 100644 deps/checksums/Pkg-b322a8ff786472d680a972e57575b4586fefe018.tar.gz/md5 delete mode 100644 deps/checksums/Pkg-b322a8ff786472d680a972e57575b4586fefe018.tar.gz/sha512 diff --git a/deps/checksums/Pkg-1c1c173d35be3eb478054fb0229b0b1b6aa040cf.tar.gz/md5 b/deps/checksums/Pkg-1c1c173d35be3eb478054fb0229b0b1b6aa040cf.tar.gz/md5 new file mode 100644 index 0000000000000..21bc73b46a108 --- /dev/null +++ b/deps/checksums/Pkg-1c1c173d35be3eb478054fb0229b0b1b6aa040cf.tar.gz/md5 @@ -0,0 +1 @@ +8893f471072bfa55bf25077d3759e951 diff --git a/deps/checksums/Pkg-1c1c173d35be3eb478054fb0229b0b1b6aa040cf.tar.gz/sha512 b/deps/checksums/Pkg-1c1c173d35be3eb478054fb0229b0b1b6aa040cf.tar.gz/sha512 new file mode 100644 index 0000000000000..b9d18c5a172ed --- /dev/null +++ b/deps/checksums/Pkg-1c1c173d35be3eb478054fb0229b0b1b6aa040cf.tar.gz/sha512 @@ -0,0 +1 @@ +6df46485c91f099501a27cb8f28688df94afa7ad877b8d1ddf9b3d210cbd5ed6c8386cb92f2f2ff6a13b855de4755f9159e0d3b9699d638b5eaf4f16513c58d1 diff --git a/deps/checksums/Pkg-b322a8ff786472d680a972e57575b4586fefe018.tar.gz/md5 b/deps/checksums/Pkg-b322a8ff786472d680a972e57575b4586fefe018.tar.gz/md5 deleted file mode 100644 index fbc81b025a8f9..0000000000000 --- a/deps/checksums/Pkg-b322a8ff786472d680a972e57575b4586fefe018.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -9fbd2f2f522bf0b5fd0d6b40f722db49 diff --git a/deps/checksums/Pkg-b322a8ff786472d680a972e57575b4586fefe018.tar.gz/sha512 b/deps/checksums/Pkg-b322a8ff786472d680a972e57575b4586fefe018.tar.gz/sha512 deleted file mode 100644 index 576ad3c62915e..0000000000000 --- a/deps/checksums/Pkg-b322a8ff786472d680a972e57575b4586fefe018.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -77e2f3729e58b74cfdd1fc2d991fc6552e7f7ceb7b9fdc837e5885932e2f15d6ab3c76b6ab90b1a6c66050dab7279abc0b976ee52b840b757dd13b1a955f5c5c From 0429a63482c0387ea7ff5ed43931be1d93595b1a Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Thu, 29 Jan 2026 12:14:06 +0100 Subject: [PATCH 61/83] compiler/ssair: preserve negative NewSSAValue (#60688) During incremental compaction a forwarded NewSSAValue with a negative id was treated like an SSAValue, producing SSAValue(-n) and tripping `renumber_ssa2` bounds checks. Only convert NewSSAValue to SSAValue when the id is positive, so new_new_nodes references remain valid. Fixes #57827. --- Compiler/src/ssair/ir.jl | 5 ++++- Compiler/test/irpasses.jl | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Compiler/src/ssair/ir.jl b/Compiler/src/ssair/ir.jl index d7f0dbedcbec5..dc75738267eab 100644 --- a/Compiler/src/ssair/ir.jl +++ b/Compiler/src/ssair/ir.jl @@ -1675,7 +1675,10 @@ function process_node!(compact::IncrementalCompact, result_idx::Int, inst::Instr stmt = ssa_rename[stmt.id] end elseif isa(stmt, NewSSAValue) - stmt = SSAValue(stmt.id) + if stmt.id > 0 + # Negative ids reference new_new_nodes and must remain NewSSAValue. + stmt = SSAValue(stmt.id) + end else # Constant assign, replace uses of this ssa value with its result end diff --git a/Compiler/test/irpasses.jl b/Compiler/test/irpasses.jl index 77a66ec6435fa..6e087f048beae 100644 --- a/Compiler/test/irpasses.jl +++ b/Compiler/test/irpasses.jl @@ -2059,3 +2059,19 @@ let src = code_typed1((Vector{Any},)) do xs end @test count(iscall((src, Core.svec)), src.code) == 1 end + +# Negative NewSSAValue ids must be preserved during compaction +function f_57827(op, init, x) + v = op(init, x) + i = 0 + while i < 1 + v = op(v, x) + i += 1 + end + return v +end +let rf = (acc, x) -> ifelse(x > acc[1], (x,), (acc[1],)) + @test f_57827(rf, (0.0,), 1) === (1,) + ir = first(only(Base.code_ircode(f_57827, (typeof(rf), Tuple{Float64}, Int64); optimize_until="CC: SROA"))) + @test ir isa Compiler.IRCode +end From eaba5ed2138bc6b14440b044e8728c4ef2418121 Mon Sep 17 00:00:00 2001 From: Oscar Smith Date: Thu, 29 Jan 2026 06:10:28 -0500 Subject: [PATCH 62/83] Fix typo in partially_inline! (#60854) Found by claude-code debugging a random zygote issue: https://github.com/SciML/NeuralPDE.jl/pull/1020#issuecomment-3799139274. `spvals` just doesn't exist within this function. This issue has apparently existed since Julia 1.6 --- base/meta.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/meta.jl b/base/meta.jl index 4807b910c494a..79497f6e6d068 100644 --- a/base/meta.jl +++ b/base/meta.jl @@ -409,7 +409,7 @@ function _partially_inline!(@nospecialize(x), slot_replacements::Vector{Any}, end return x elseif head === :cfunction - @assert !isa(type_signature, UnionAll) || !isempty(spvals) + @assert !isa(type_signature, UnionAll) || !isempty(static_param_values) if !isa(x.args[2], QuoteNode) # very common no-op x.args[2] = _partially_inline!(x.args[2], slot_replacements, type_signature, static_param_values, slot_offset, From be1545c8c1b5205ca37c85be2f638bf342db5b60 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Thu, 29 Jan 2026 12:23:53 +0100 Subject: [PATCH 63/83] ssair: fix phi edge cleanup for current block (#60697) --- Compiler/src/ssair/ir.jl | 26 +++++++++++++++++++------- Compiler/test/ssair.jl | 31 +++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/Compiler/src/ssair/ir.jl b/Compiler/src/ssair/ir.jl index dc75738267eab..431ee63f57788 100644 --- a/Compiler/src/ssair/ir.jl +++ b/Compiler/src/ssair/ir.jl @@ -1373,8 +1373,19 @@ function kill_edge!(ir::IRCode, from::Int, to::Int, callback=nothing) kill_edge!(ir.cfg.blocks, from, to, callback) end -# N.B.: from and to are non-renamed indices -function kill_edge!(compact::IncrementalCompact, active_bb::Int, from::Int, to::Int) +@inline function compacted_stmt_range(compact::IncrementalCompact, bb::BasicBlock, active_bb::Int, to::Int) + to == active_bb && return StmtRange(first(bb.stmts), compact.result_idx - 1) + return bb.stmts +end + +""" + kill_edge_terminator!(compact::IncrementalCompact, active_bb::Int, from::Int, to::Int) + +Kill a CFG edge while compacting a terminator in `active_bb`. Assumes all PhiNode +block statements in `to` have already been processed, so the active BB may only +scan the compacted prefix when `to == active_bb`. `from` and `to` are non-renamed indices. +""" +function kill_edge_terminator!(compact::IncrementalCompact, active_bb::Int, from::Int, to::Int) # Note: We recursively kill as many edges as are obviously dead. (; bb_rename_pred, bb_rename_succ, result_bbs, domtree) = compact.cfg_transform preds = result_bbs[bb_rename_succ[to]].preds @@ -1390,7 +1401,7 @@ function kill_edge!(compact::IncrementalCompact, active_bb::Int, from::Int, to:: for succ in copy(to_succs) new_succ = findfirst(x::Int->x==succ, bb_rename_pred) new_succ === nothing && continue - kill_edge!(compact, active_bb, to, new_succ) + kill_edge_terminator!(compact, active_bb, to, new_succ) end empty!(preds) empty!(to_succs) @@ -1412,8 +1423,9 @@ function kill_edge!(compact::IncrementalCompact, active_bb::Int, from::Int, to:: # Remove this edge from all phi nodes in `to` block # NOTE: It is possible for `to` to contain only `nothing` statements, # so we must be careful to stop at its last statement - if to < active_bb - stmts = result_bbs[bb_rename_succ[to]].stmts + if to <= active_bb + bb = result_bbs[bb_rename_succ[to]] + stmts = compacted_stmt_range(compact, bb, active_bb, to) idx = first(stmts) while idx <= last(stmts) stmt = compact.result[idx][:stmt] @@ -1493,14 +1505,14 @@ function process_node!(compact::IncrementalCompact, result_idx::Int, inst::Instr if cond ssa_rename[idx] = nothing result[result_idx][:stmt] = nothing - kill_edge!(compact, active_bb, active_bb, stmt.dest) + kill_edge_terminator!(compact, active_bb, active_bb, stmt.dest) # Don't increment result_idx => Drop this statement else label = bb_rename_succ[stmt.dest] @assert label > 0 ssa_rename[idx] = SSAValue(result_idx) result[result_idx][:stmt] = GotoNode(label) - kill_edge!(compact, active_bb, active_bb, active_bb+1) + kill_edge_terminator!(compact, active_bb, active_bb, active_bb+1) result_idx += 1 end else diff --git a/Compiler/test/ssair.jl b/Compiler/test/ssair.jl index f7ceda07601e2..c9228b30d9e17 100644 --- a/Compiler/test/ssair.jl +++ b/Compiler/test/ssair.jl @@ -108,6 +108,21 @@ let cfg = CFG(BasicBlock[ @test length(compact.cfg_transform.result_bbs) == 4 && 0 in compact.cfg_transform.result_bbs[3].preds end +# Test that removing a self-edge during compaction only scans compacted phi statements. +let code = Any[ + # Block 1 + Compiler.GotoNode(2), + # Block 2 + Core.PhiNode(Int32[1, 3], Any[1, 2]), + Compiler.GotoIfNot(true, 2), + # Block 3 + Compiler.ReturnNode(0), + ] + ir = make_ircode(code) + ir = Compiler.compact!(ir, true) + @test Compiler.verify_ir(ir) === nothing +end + # Issue #32579 - Optimizer bug involving type constraints function f32579(x::Int, b::Bool) if b @@ -850,3 +865,19 @@ let ir = Compiler.inflate_ir!(ci, mi) @test ir isa Compiler.IRCode end + +# Tests that CFG edge cleanup during compaction doesn't corrupt iteration codegen. +Trips_60660 = let + Ts = (Float64, Float32) + [(Ta, Tb, Tc) for Ta in Ts for Tb in Ts for Tc in Ts] +end +@test Trips_60660 == [ + (Float64, Float64, Float64), + (Float64, Float64, Float32), + (Float64, Float32, Float64), + (Float64, Float32, Float32), + (Float32, Float64, Float64), + (Float32, Float64, Float32), + (Float32, Float32, Float64), + (Float32, Float32, Float32), +] From f5754389fdda854ad1bc2a7b6a2c6f4232d58bd1 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Thu, 29 Jan 2026 20:44:31 +0900 Subject: [PATCH 64/83] inference: fix union split handling for custom lattices (#60857) `MustAlias` has `has_extended_unionsplit(::MustAliasLattice) === true` so it is treated as a target for union split, but `uniontypes` does not handle `MustAlias` specially, causing union split to fail for `MustAlias`. This issue is addressed by always applying `uniontypes` to the result of `widenconst(x)`. External custom lattice implementations could previously provide their own `uniontypes`, but it would be cleaner interface design if they just overload `widenconst` for their custom lattice elements so that it returns `Union`-type. --- Compiler/src/typeutils.jl | 5 +++-- Compiler/test/inference.jl | 9 +++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Compiler/src/typeutils.jl b/Compiler/src/typeutils.jl index 50b3dc6b0c6f5..5abae32cdb7d6 100644 --- a/Compiler/src/typeutils.jl +++ b/Compiler/src/typeutils.jl @@ -277,8 +277,9 @@ function _switchtupleunion(𝕃::AbstractLattice, t::Vector{Any}, i::Int, tunion _switchtupleunion(𝕃, t, i - 1, tunion, origt) end t[i] = origti - elseif has_extended_unionsplit(𝕃) && !isa(ti, Const) && !isvarargtype(ti) && isa(widenconst(ti), Union) - for ty in uniontypes(ti) + elseif (has_extended_unionsplit(𝕃) && !isa(ti, Const) && !isvarargtype(ti) && + (wty = widenconst(ti); isa(wty, Union))) + for ty in uniontypes(wty) t[i] = ty _switchtupleunion(𝕃, t, i - 1, tunion, origt) end diff --git a/Compiler/test/inference.jl b/Compiler/test/inference.jl index 6b1b964805149..a4bb3773366a3 100644 --- a/Compiler/test/inference.jl +++ b/Compiler/test/inference.jl @@ -2591,6 +2591,15 @@ end == Integer Val(isdefined(xxx.value, :x)) end == Val{true} +# Test union splitting for MustAlias +struct GetSomethingA; x::Union{Nothing,Int}; end +struct GetSomethingB; x::Int; end +getsomethingx(a::GetSomethingA) = something(a.x, 0) +getsomethingx(b::GetSomethingB) = b.x +@test Base.infer_return_type((Union{GetSomethingA,GetSomethingB},); interp=MustAliasInterpreter()) do x + getsomethingx(x) +end == Int + @testset "issue #56913: `BoundsError` in type inference" begin R = UnitRange{Int} @test Type{AbstractVector} == Base.infer_return_type(Base.promote_typeof, Tuple{R, R, Vector{Any}, Vararg{R}}) From 4938a3e3389335a56feb5e5fdf0763d8b6b65b3a Mon Sep 17 00:00:00 2001 From: rokke <66498307+rokke-git@users.noreply.github.com> Date: Wed, 28 Jan 2026 00:16:20 -0500 Subject: [PATCH 65/83] Merge pull request #60834 from rokke-git/patch-5 Test suite: switch to `httpbingo.julialang`, fall back to `httpbin.julialang` on failure (cherry picked from commit 5ab8db39c014dfcf1b53314932dddfea35ecb2c7) (cherry picked from commit e4cfa466a924b03fc102161c448251b2bfbe0d38) --- test/download_exec.jl | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/test/download_exec.jl b/test/download_exec.jl index 777fb6773c463..93af540dd70a1 100644 --- a/test/download_exec.jl +++ b/test/download_exec.jl @@ -5,22 +5,31 @@ module TestDownload using Test mktempdir() do temp_dir + url = try + download("https://httpbingo.julialang.org") + "https://httpbingo.julialang.org" + catch ex + bt = catch_backtrace() + @info "Looks like there is a problem with a JuliaLang mirror of httpbingo" + @info "Trying httpbin" exception=(ex,bt) + "https://httpbin.julialang.org/" + end # Download a file file = joinpath(temp_dir, "ip") - @test download("https://httpbin.julialang.org/ip", file) == file + @test download("$url/ip", file) == file @test isfile(file) @test !isempty(read(file)) ip = read(file, String) # Download an empty file empty_file = joinpath(temp_dir, "empty") - @test download("https://httpbin.julialang.org/status/200", empty_file) == empty_file + @test download("$url/status/200", empty_file) == empty_file @test isfile(empty_file) @test isempty(read(empty_file)) # Make sure that failed downloads do not leave files around missing_file = joinpath(temp_dir, "missing") - @test_throws Exception download("https://httpbin.julialang.org/status/404", missing_file) + @test_throws Exception download("$url/status/404", missing_file) @test !isfile(missing_file) # Use a TEST-NET (192.0.2.0/24) address which shouldn't be bound From 91f65e4e42802394befde37064aae3ed9797f886 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 03:13:48 +0000 Subject: [PATCH 66/83] [release-1.12] Bump julia-actions/setup-julia from 2.6.0 to 2.6.1 Bumps [julia-actions/setup-julia](https://github.com/julia-actions/setup-julia) from 2.6.0 to 2.6.1. - [Release notes](https://github.com/julia-actions/setup-julia/releases) - [Commits](https://github.com/julia-actions/setup-julia/compare/9b79636afcfb07ab02c256cede01fe2db6ba808c...5c9647d97b78a5debe5164e9eec09d653d29bd71) --- updated-dependencies: - dependency-name: julia-actions/setup-julia dependency-version: 2.6.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/Whitespace.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Whitespace.yml b/.github/workflows/Whitespace.yml index 37c9dbfd39a3c..0855811c4ece6 100644 --- a/.github/workflows/Whitespace.yml +++ b/.github/workflows/Whitespace.yml @@ -18,7 +18,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: persist-credentials: false - - uses: julia-actions/setup-julia@9b79636afcfb07ab02c256cede01fe2db6ba808c # v2.6.0 + - uses: julia-actions/setup-julia@5c9647d97b78a5debe5164e9eec09d653d29bd71 # v2.6.1 with: version: '1' - name: Check whitespace From 990220f82a3d01c475d52f868e212d237897531b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 03:13:54 +0000 Subject: [PATCH 67/83] [release-1.12] Bump actions/checkout from 4.1.7 to 6.0.2 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.7 to 6.0.2. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/692973e3d937129bcbf40652eb9f2f61becf3332...de0fac2e4500dabe0009e67214ff5f5447ce83dd) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.2 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/Typos.yml | 2 +- .github/workflows/Whitespace.yml | 2 +- .github/workflows/cffconvert.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/Typos.yml b/.github/workflows/Typos.yml index 6c9eeacc21800..25cf9fea7cd0b 100644 --- a/.github/workflows/Typos.yml +++ b/.github/workflows/Typos.yml @@ -11,7 +11,7 @@ jobs: timeout-minutes: 5 steps: - name: Checkout the JuliaLang/julia repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Check spelling with typos diff --git a/.github/workflows/Whitespace.yml b/.github/workflows/Whitespace.yml index 37c9dbfd39a3c..28e8153316a0f 100644 --- a/.github/workflows/Whitespace.yml +++ b/.github/workflows/Whitespace.yml @@ -15,7 +15,7 @@ jobs: timeout-minutes: 2 steps: - name: Checkout the JuliaLang/julia repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: julia-actions/setup-julia@9b79636afcfb07ab02c256cede01fe2db6ba808c # v2.6.0 diff --git a/.github/workflows/cffconvert.yml b/.github/workflows/cffconvert.yml index 4c9debb246f3f..45f19078a8af8 100644 --- a/.github/workflows/cffconvert.yml +++ b/.github/workflows/cffconvert.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out a copy of the repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false From 5fe89b8ddc166260bfcd4a195b305aff0ccad686 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Mon, 9 Feb 2026 17:05:41 +0100 Subject: [PATCH 68/83] set VERSION to 1.12.5 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 89c881bc9cb92..e0a6b34fb0aa0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.12.4 +1.12.5 From 1966e88aadb43f5931dcd9c29298a080aef136cc Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Fri, 5 Dec 2025 09:10:31 -0700 Subject: [PATCH 69/83] RAI: Add 'RAI' as the build part of the semantic version --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index e0a6b34fb0aa0..3c27091f99178 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.12.5 +1.12.5+RAI From 828975884dd85400e3292b3af0f12d4e89722a32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Drvo=C5=A1t=C4=9Bp?= Date: Tue, 19 Mar 2024 18:35:13 +0100 Subject: [PATCH 70/83] Add GitHub template and workflows needed on the default branch (#135) --- .github/labeler.yml | 3 ++ .github/pull_request_template.md | 14 ++++++++++ .github/workflows/labeler.yml | 17 +++++++++++ .github/workflows/stale.yml | 16 +++++++++++ .../workflows/update-upstream-branches.yml | 28 +++++++++++++++++++ 5 files changed, 78 insertions(+) create mode 100644 .github/labeler.yml create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/labeler.yml create mode 100644 .github/workflows/stale.yml create mode 100644 .github/workflows/update-upstream-branches.yml diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000000000..9359bd0ca70a6 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,3 @@ +# See https://github.com/actions/labeler +port-to-master: '**' +port-to-v1.10: '**' diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000000..7ed825781c53b --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,14 @@ + +## PR Description + +_What does this PR do?_ + +## Checklist + +Requirements for merging: +- [ ] I have opened an issue or PR upstream on JuliaLang/julia: +- [ ] I have removed the `port-to-*` labels that don't apply. +- [ ] I have opened a PR on raicode to test these changes: diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 0000000000000..2141a906e96cd --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,17 @@ +# See https://github.com/actions/labeler +name: "Pull Request Labeler" +on: + pull_request_target: + types: + - opened + +jobs: + triage: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v4 + with: + dot: true diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000000000..3df2093491753 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,16 @@ +name: "Close stale PRs" +on: + schedule: + - cron: "0 0 * * *" # every night at midnight + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v8 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-pr-message: 'This PR is stale because it has been open 30 days with no activity. Comment or remove stale label, or this PR will be closed in 5 days.' + days-before-stale: 30 + days-before-close: 5 + stale-pr-label: 'stale' diff --git a/.github/workflows/update-upstream-branches.yml b/.github/workflows/update-upstream-branches.yml new file mode 100644 index 0000000000000..247000bbd42cd --- /dev/null +++ b/.github/workflows/update-upstream-branches.yml @@ -0,0 +1,28 @@ +name: "Update upstream branches" +on: + schedule: + - cron: "0 0 * * *" # every night at midnight + workflow_dispatch: + +jobs: + PullUpstream: + runs-on: ubuntu-latest + strategy: + fail-fast: false # run all jobs in the matrix even if one fails + matrix: + branch: + - "master" + - "backports-release-1.10" + steps: + - name: Checkout RAI/julia + uses: actions/checkout@v3 + with: + ref: ${{ matrix.branch }} + - name: Update ${{ matrix.branch }} + run: | + git config --global user.email "julia-engineering@relational.ai" + git config --global user.name "RAI CI (GitHub Action Automation)" + + git remote add upstream https://github.com/JuliaLang/julia + git pull upstream ${{ matrix.branch }} + git push origin ${{ matrix.branch }} From 66166470c132c6920a1e1d3b900674893e2f29ba Mon Sep 17 00:00:00 2001 From: d-netto Date: Mon, 6 Jan 2025 10:06:00 -0300 Subject: [PATCH 71/83] RAI: Track blocks and bytes allocated for GC pools --- src/gc-pages.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/gc-pages.c b/src/gc-pages.c index 71d59de29166f..7cb1fb1c33bc3 100644 --- a/src/gc-pages.c +++ b/src/gc-pages.c @@ -28,6 +28,28 @@ JL_DLLEXPORT uint64_t jl_get_pg_size(void) static int block_pg_cnt = DEFAULT_BLOCK_PG_ALLOC; +// Julia allocates large blocks (64M) with mmap. These are never +// unmapped but the underlying physical memory may be released +// with calls to madvise(MADV_DONTNEED). +static uint64_t poolmem_blocks_allocated_total = 0; + +JL_DLLEXPORT uint64_t jl_poolmem_blocks_allocated_total(void) +{ + return poolmem_blocks_allocated_total; +} + +JL_DLLEXPORT uint64_t jl_poolmem_bytes_allocated(void) +{ + return jl_atomic_load_relaxed(&gc_heap_stats.bytes_resident); +} + +JL_DLLEXPORT uint64_t jl_current_pg_count(void) +{ + assert(jl_page_size == GC_PAGE_SZ && "RAI fork of Julia should be running on platforms for which jl_page_size == GC_PAGE_SZ"); + size_t nb = jl_atomic_load_relaxed(&gc_heap_stats.bytes_resident); + return nb / GC_PAGE_SZ; // exact division +} + void jl_gc_init_page(void) { if (GC_PAGE_SZ * block_pg_cnt < jl_page_size) @@ -62,6 +84,7 @@ char *jl_gc_try_alloc_pages_(int pg_cnt) JL_NOTSAFEPOINT mem = (char*)gc_page_data(mem + GC_PAGE_SZ - 1); jl_atomic_fetch_add_relaxed(&gc_heap_stats.bytes_mapped, pages_sz); jl_atomic_fetch_add_relaxed(&gc_heap_stats.bytes_resident, pages_sz); + poolmem_blocks_allocated_total++; // RAI-specific return mem; } From e5763705188978811a557663f9ac2af0c49c088b Mon Sep 17 00:00:00 2001 From: K Pamnany Date: Wed, 9 Aug 2023 12:57:35 -0400 Subject: [PATCH 72/83] RAI: Change task ordering behavior to prioritize older tasks --- base/partr.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/partr.jl b/base/partr.jl index d488330f0c87e..671c88fd6e786 100644 --- a/base/partr.jl +++ b/base/partr.jl @@ -97,7 +97,7 @@ function multiq_sift_down(heap::taskheap, idx::Int32) child = Int(child) child > length(heap.tasks) && break if isassigned(heap.tasks, child) && - heap.tasks[child].priority < heap.tasks[idx].priority + heap.tasks[child].priority <= heap.tasks[idx].priority t = heap.tasks[idx] heap.tasks[idx] = heap.tasks[child] heap.tasks[child] = t From edf4b9a7d446624ab293d2bd684f5c19beca7464 Mon Sep 17 00:00:00 2001 From: K Pamnany Date: Mon, 21 Aug 2023 12:19:17 -0400 Subject: [PATCH 73/83] RAI: Disable huge pages for all mmap'ed memory Prevent transparent huge pages (THP) overallocating pysical memory. Co-authored-by: Adnan Alhomssi --- src/gc-pages.c | 5 +++++ src/gc-stacks.c | 6 ++++-- src/gc-stock.c | 3 +++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/gc-pages.c b/src/gc-pages.c index 7cb1fb1c33bc3..f92a9ae828c12 100644 --- a/src/gc-pages.c +++ b/src/gc-pages.c @@ -77,6 +77,11 @@ char *jl_gc_try_alloc_pages_(int pg_cnt) JL_NOTSAFEPOINT MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (mem == MAP_FAILED) return NULL; + +#ifdef MADV_NOHUGEPAGE + madvise(mem, pages_sz, MADV_NOHUGEPAGE); +#endif + #endif if (GC_PAGE_SZ > jl_page_size) // round data pointer up to the nearest gc_page_data-aligned diff --git a/src/gc-stacks.c b/src/gc-stacks.c index 9387c7fb065ec..55c4a470dd33e 100644 --- a/src/gc-stacks.c +++ b/src/gc-stacks.c @@ -72,8 +72,10 @@ static void *malloc_stack(size_t bufsz) JL_NOTSAFEPOINT munmap(stk, bufsz); return MAP_FAILED; } -# endif - +#ifdef MADV_NOHUGEPAGE + madvise(stk, bufsz, MADV_NOHUGEPAGE); +#endif +#endif jl_atomic_fetch_add_relaxed(&num_stack_mappings, 1); return stk; } diff --git a/src/gc-stock.c b/src/gc-stock.c index a95dc5f731a5b..0bcbfe4f87c86 100644 --- a/src/gc-stock.c +++ b/src/gc-stock.c @@ -3916,6 +3916,9 @@ void *jl_gc_perm_alloc_nolock(size_t sz, int zero, unsigned align, unsigned offs errno = last_errno; if (__unlikely(pool == MAP_FAILED)) return NULL; +#ifdef MADV_NOHUGEPAGE + madvise(pool, GC_PERM_POOL_SIZE, MADV_NOHUGEPAGE); +#endif #endif gc_perm_pool = (uintptr_t)pool; gc_perm_end = gc_perm_pool + GC_PERM_POOL_SIZE; From 5e6cc5c92e57396226dc51c1c8f657ce2e15e6bf Mon Sep 17 00:00:00 2001 From: "Bradley C. Kuszmaul" Date: Tue, 22 Aug 2023 14:27:07 -0400 Subject: [PATCH 74/83] RAI: Never use MADV_FREE --- src/gc-pages.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gc-pages.c b/src/gc-pages.c index f92a9ae828c12..79dd8993a8861 100644 --- a/src/gc-pages.c +++ b/src/gc-pages.c @@ -212,7 +212,7 @@ void jl_gc_free_page(jl_gc_pagemeta_t *pg) JL_NOTSAFEPOINT } #ifdef _OS_WINDOWS_ VirtualFree(p, decommit_size, MEM_DECOMMIT); -#elif defined(MADV_FREE) +#elif 0 static int supports_madv_free = 1; if (supports_madv_free) { if (madvise(p, decommit_size, MADV_FREE) == -1) { From 6a5344b66ef95520ea252b01b89ac518557edf92 Mon Sep 17 00:00:00 2001 From: K Pamnany Date: Mon, 9 Oct 2023 16:32:13 -0400 Subject: [PATCH 75/83] RAI: Prepend "thread (%d) " to output from `jl_print_task_backtraces()` --- src/stackwalk.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/stackwalk.c b/src/stackwalk.c index 50566b46ff45a..2a9dea558b191 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -1415,6 +1415,8 @@ JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT { size_t nthreads = jl_atomic_load_acquire(&jl_n_threads); jl_ptls_t *allstates = jl_atomic_load_relaxed(&jl_all_tls_states); + int ctid = jl_threadid() + 1; + jl_safe_printf("thread (%d) ++++ Task backtraces\n", ctid); for (size_t i = 0; i < nthreads; i++) { jl_ptls_t ptls2 = allstates[i]; if (gc_is_collector_thread(i)) { @@ -1430,17 +1432,22 @@ JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT jl_task_t *t = ptls2->root_task; if (t != NULL) t_state = jl_atomic_load_relaxed(&t->_state); - jl_safe_printf("==== Thread %d created %zu live tasks\n", - ptls2->tid + 1, n + (t_state != JL_TASK_STATE_DONE)); + jl_safe_printf("thread (%d) ==== Thread %d created %zu live tasks\n", + ctid, ptls2->tid + 1, n + (t_state != JL_TASK_STATE_DONE)); if (show_done || t_state != JL_TASK_STATE_DONE) { - jl_safe_printf(" ---- Root task (%p)\n", ptls2->root_task); + jl_safe_printf("thread (%d) ---- Root task (%p)\n", ctid, ptls2->root_task); if (t != NULL) { - jl_safe_printf(" (sticky: %d, started: %d, state: %d, tid: %d)\n", - t->sticky, t->ctx.started, t_state, + jl_safe_printf("thread (%d) (sticky: %d, started: %d, state: %d, tid: %d)\n", + ctid, t->sticky, t->ctx.started, t_state, jl_atomic_load_relaxed(&t->tid) + 1); - jlbacktracet(t); + if (t->ctx.stkbuf != NULL) { + jlbacktracet(t); + } + else { + jl_safe_printf("thread (%d) no stack\n", ctid); + } } - jl_safe_printf(" ---- End root task\n"); + jl_safe_printf("thread (%d) ---- End root task\n", ctid); } for (size_t j = 0; j < n; j++) { @@ -1450,17 +1457,20 @@ JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT int t_state = jl_atomic_load_relaxed(&t->_state); if (!show_done && t_state == JL_TASK_STATE_DONE) continue; - jl_safe_printf(" ---- Task %zu (%p)\n", j + 1, t); + jl_safe_printf("thread (%d) ---- Task %zu (%p)\n", ctid, j + 1, t); // n.b. this information might not be consistent with the stack printing after it, since it could start running or change tid, etc. - jl_safe_printf(" (sticky: %d, started: %d, state: %d, tid: %d)\n", - t->sticky, t->ctx.started, t_state, + jl_safe_printf("thread (%d) (sticky: %d, started: %d, state: %d, tid: %d)\n", + ctid, t->sticky, t->ctx.started, t_state, jl_atomic_load_relaxed(&t->tid) + 1); - jlbacktracet(t); - jl_safe_printf(" ---- End task %zu\n", j + 1); + if (t->ctx.stkbuf != NULL) + jlbacktracet(t); + else + jl_safe_printf("thread (%d) no stack\n", ctid); + jl_safe_printf("thread (%d) ---- End task %zu\n", ctid, j + 1); } - jl_safe_printf("==== End thread %d\n", ptls2->tid + 1); + jl_safe_printf("thread (%d) ==== End thread %d\n", ctid, ptls2->tid + 1); } - jl_safe_printf("==== Done\n"); + jl_safe_printf("thread (%d) ++++ Done\n", ctid); } #ifdef __cplusplus From 15c1feae605e33a62621401fb2df11114fd05c82 Mon Sep 17 00:00:00 2001 From: K Pamnany Date: Sat, 7 Oct 2023 18:30:01 -0400 Subject: [PATCH 76/83] RAI: Add heartbeat capability --- src/gc-stock.c | 5 + src/gc-stock.h | 3 + src/init.c | 7 ++ src/julia_internal.h | 2 + src/options.h | 3 + src/signals-mach.c | 4 + src/signals-unix.c | 4 + src/stackwalk.c | 19 ++- src/threading.c | 283 +++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 329 insertions(+), 1 deletion(-) diff --git a/src/gc-stock.c b/src/gc-stock.c index 0bcbfe4f87c86..a56e61cdec37f 100644 --- a/src/gc-stock.c +++ b/src/gc-stock.c @@ -3407,6 +3407,9 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) return recollect; } +extern int jl_heartbeat_pause(void); +extern int jl_heartbeat_resume(void); + JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection) { JL_PROBE_GC_BEGIN(collection); @@ -3449,6 +3452,7 @@ JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection) // existence of the thread in the jl_n_threads count. // // TODO: concurrently queue objects + jl_heartbeat_pause(); jl_fence(); gc_n_threads = jl_atomic_load_acquire(&jl_n_threads); gc_all_tls_states = jl_atomic_load_relaxed(&jl_all_tls_states); @@ -3480,6 +3484,7 @@ JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection) gc_n_threads = 0; gc_all_tls_states = NULL; + jl_heartbeat_resume(); jl_safepoint_end_gc(); jl_gc_state_set(ptls, old_state, JL_GC_STATE_WAITING); JL_PROBE_GC_END(); diff --git a/src/gc-stock.h b/src/gc-stock.h index 3abd42ea1bfd3..fb55a2e8fa9bd 100644 --- a/src/gc-stock.h +++ b/src/gc-stock.h @@ -500,6 +500,9 @@ extern uv_sem_t gc_sweep_assists_needed; extern _Atomic(int) gc_n_threads_marking; extern _Atomic(int) gc_n_threads_sweeping_pools; extern _Atomic(int) n_threads_running; +extern _Atomic(int) gc_n_threads_sweeping_stacks; +extern _Atomic(int) gc_ptls_sweep_idx; +extern _Atomic(int) gc_stack_free_idx; extern uv_barrier_t thread_init_done; void gc_mark_queue_all_roots(jl_ptls_t ptls, jl_gc_markqueue_t *mq); void gc_mark_finlist_(jl_gc_markqueue_t *mq, jl_value_t *fl_parent, jl_value_t **fl_begin, jl_value_t **fl_end) JL_NOTSAFEPOINT; diff --git a/src/init.c b/src/init.c index f86435b3b9035..c0bd6de1e99a4 100644 --- a/src/init.c +++ b/src/init.c @@ -554,6 +554,8 @@ extern jl_mutex_t global_roots_lock; extern jl_mutex_t profile_show_peek_cond_lock; extern jl_mutex_t jl_typeinf_lock; +extern void jl_init_heartbeat(void); + static void restore_fp_env(void) { if (jl_set_zero_subnormals(0) || jl_set_default_nans(0)) { @@ -613,6 +615,11 @@ static NOINLINE void _finish_jl_init_(jl_image_buf_t sysimage, jl_ptls_t ptls, j jl_start_gc_threads(); uv_barrier_wait(&thread_init_done); + if (jl_base_module != NULL) { + // requires code in Base + jl_init_heartbeat(); + } + jl_gc_enable(1); if ((sysimage.kind != JL_IMAGE_KIND_NONE) && diff --git a/src/julia_internal.h b/src/julia_internal.h index 0d3d45f35501f..781997f871841 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -230,6 +230,7 @@ extern volatile size_t profile_bt_size_max; extern volatile size_t profile_bt_size_cur; extern volatile int profile_running; extern volatile int profile_all_tasks; +extern int heartbeat_tid; // Mostly used to ensure we skip this thread in the CPU profiler. XXX: not implemented on Windows // Ensures that we can safely read the `live_tasks`field of every TLS when profiling. // We want to avoid the case that a GC gets interleaved with `jl_profile_task` and shrinks // the `live_tasks` array while we are reading it or frees tasks that are being profiled. @@ -245,6 +246,7 @@ extern uv_mutex_t bt_data_prof_lock; #define PROFILE_STATE_THREAD_NOT_SLEEPING (1) #define PROFILE_STATE_THREAD_SLEEPING (2) #define PROFILE_STATE_WALL_TIME_PROFILING (3) +extern _Atomic(int) n_threads_running; void jl_profile_task(void); // number of cycles since power-on diff --git a/src/options.h b/src/options.h index 0715069faab32..fb2797ffd0336 100644 --- a/src/options.h +++ b/src/options.h @@ -144,6 +144,9 @@ #define MACHINE_EXCLUSIVE_NAME "JULIA_EXCLUSIVE" #define DEFAULT_MACHINE_EXCLUSIVE 0 +// heartbeats +#define JL_HEARTBEAT_THREAD + // sanitizer defaults --------------------------------------------------------- // Automatically enable MEMDEBUG and KEEP_BODIES for the sanitizers diff --git a/src/signals-mach.c b/src/signals-mach.c index 4a670547bdfcd..12d545ee81ce6 100644 --- a/src/signals-mach.c +++ b/src/signals-mach.c @@ -824,6 +824,10 @@ void *mach_profile_listener(void *arg) for (int idx = nthreads; idx-- > 0; ) { // Stop the threads in random order. int i = randperm[idx]; + // skip heartbeat thread + if (i == heartbeat_tid) { + continue; + } jl_profile_thread_mach(i); } } diff --git a/src/signals-unix.c b/src/signals-unix.c index 2db397050420e..550f3303aa2b1 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -873,6 +873,10 @@ static void do_profile(void *ctx) for (int idx = nthreads; idx-- > 0; ) { // Stop the threads in the random order. int tid = randperm[idx]; + // skip heartbeat thread + if (tid == heartbeat_tid) { + return; + } // do backtrace for profiler if (!profile_running) return; diff --git a/src/stackwalk.c b/src/stackwalk.c index 2a9dea558b191..410f4028b6704 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -1410,9 +1410,22 @@ JL_DLLEXPORT void jl_print_backtrace(void) JL_NOTSAFEPOINT jlbacktrace(); } -// Print backtraces for all live tasks, for all threads, to jl_safe_printf stderr +extern int jl_inside_heartbeat_thread(void); +extern int jl_heartbeat_pause(void); +extern int jl_heartbeat_resume(void); + +// Print backtraces for all live tasks, for all threads, to jl_safe_printf +// stderr. This can take a _long_ time! JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT { + // disable heartbeats to prevent heartbeat loss while running this, + // unless this is called from the heartbeat thread itself; in that + // situation, the thread is busy running this and it will not be + // updating the missed heartbeats counter + if (!jl_inside_heartbeat_thread()) { + jl_heartbeat_pause(); + } + size_t nthreads = jl_atomic_load_acquire(&jl_n_threads); jl_ptls_t *allstates = jl_atomic_load_relaxed(&jl_all_tls_states); int ctid = jl_threadid() + 1; @@ -1471,6 +1484,10 @@ JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT jl_safe_printf("thread (%d) ==== End thread %d\n", ctid, ptls2->tid + 1); } jl_safe_printf("thread (%d) ++++ Done\n", ctid); + + if (!jl_inside_heartbeat_thread()) { + jl_heartbeat_resume(); + } } #ifdef __cplusplus diff --git a/src/threading.c b/src/threading.c index 9f5c18fe53555..e56aba2de51a1 100644 --- a/src/threading.c +++ b/src/threading.c @@ -1111,6 +1111,289 @@ JL_DLLEXPORT int jl_setaffinity(int16_t tid, char *mask, int cpumasksize) { return 0; // success } +// Heartbeat mechanism for Julia's task scheduler +// --- +// Start a thread that does not participate in running Julia's tasks. This +// thread simply sleeps until the heartbeat mechanism is enabled. When +// enabled, the heartbeat thread enters a loop in which it blocks waiting +// for the specified heartbeat interval. If, within that interval, +// `jl_heartbeat()` is *not* called at least once, then the thread calls +// `jl_print_task_backtraces(0)`. + +#ifdef JL_HEARTBEAT_THREAD + +#include + +volatile int heartbeat_enabled; +int heartbeat_tid; // Mostly used to ensure we skip this thread in the CPU profiler. XXX: not implemented on Windows +uv_thread_t heartbeat_uvtid; +uv_sem_t heartbeat_on_sem, // jl_heartbeat_enable -> thread + heartbeat_off_sem; // thread -> jl_heartbeat_enable +int heartbeat_interval_s, + tasks_after_n, + reset_tasks_after_n; +int tasks_showed, n_hbs_missed, n_hbs_recvd; +_Atomic(int) heartbeats; + +JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT; +void jl_heartbeat_threadfun(void *arg); + +// start the heartbeat thread with heartbeats disabled +void jl_init_heartbeat(void) +{ + heartbeat_enabled = 0; + uv_sem_init(&heartbeat_on_sem, 0); + uv_sem_init(&heartbeat_off_sem, 0); + uv_thread_create(&heartbeat_uvtid, jl_heartbeat_threadfun, NULL); + uv_thread_detach(&heartbeat_uvtid); +} + +int jl_inside_heartbeat_thread(void) +{ + uv_thread_t curr_uvtid = uv_thread_self(); + return curr_uvtid == heartbeat_uvtid; +} + +// enable/disable heartbeats +// heartbeat_s: interval within which jl_heartbeat() must be called +// show_tasks_after_n: number of heartbeats missed before printing task backtraces +// reset_after_n: number of heartbeats after which to reset +// +// When disabling heartbeats, the heartbeat thread must wake up, +// find out that heartbeats are now disabled, and reset. For now, we +// handle this by preventing re-enabling of heartbeats until this +// completes. +JL_DLLEXPORT int jl_heartbeat_enable(int heartbeat_s, int show_tasks_after_n, + int reset_after_n) +{ + if (heartbeat_s <= 0) { + heartbeat_enabled = 0; + heartbeat_interval_s = tasks_after_n = reset_tasks_after_n = 0; + } + else { + // must disable before enabling + if (heartbeat_enabled) { + return -1; + } + // heartbeat thread must be ready + if (uv_sem_trywait(&heartbeat_off_sem) != 0) { + return -1; + } + + jl_atomic_store_relaxed(&heartbeats, 0); + heartbeat_interval_s = heartbeat_s; + tasks_after_n = show_tasks_after_n; + reset_tasks_after_n = reset_after_n; + tasks_showed = 0; + n_hbs_missed = 0; + n_hbs_recvd = 0; + heartbeat_enabled = 1; + uv_sem_post(&heartbeat_on_sem); // wake the heartbeat thread + } + return 0; +} + +// temporarily pause the heartbeat thread +JL_DLLEXPORT int jl_heartbeat_pause(void) +{ + if (!heartbeat_enabled) { + return -1; + } + heartbeat_enabled = 0; + return 0; +} + +// resume the paused heartbeat thread +JL_DLLEXPORT int jl_heartbeat_resume(void) +{ + // cannot resume if the heartbeat thread is already running + if (heartbeat_enabled) { + return -1; + } + + // cannot resume if we weren't paused (disabled != paused) + if (heartbeat_interval_s == 0) { + return -1; + } + + // heartbeat thread must be ready + if (uv_sem_trywait(&heartbeat_off_sem) != 0) { + return -1; + } + + // reset state as we've been paused + n_hbs_missed = 0; + n_hbs_recvd = 0; + tasks_showed = 0; + + // resume + heartbeat_enabled = 1; + uv_sem_post(&heartbeat_on_sem); // wake the heartbeat thread + return 0; +} + +// heartbeat +JL_DLLEXPORT void jl_heartbeat(void) +{ + jl_atomic_fetch_add(&heartbeats, 1); +} + +// sleep the thread for the specified interval +void sleep_for(int secs, int nsecs) +{ + struct timespec rqtp, rmtp; + rqtp.tv_sec = secs; + rqtp.tv_nsec = nsecs; + rmtp.tv_sec = 0; + rmtp.tv_nsec = 0; + for (; ;) { + // this suspends the thread so we aren't using CPU + if (nanosleep(&rqtp, &rmtp) == 0) { + return; + } + // TODO: else if (errno == EINTR) + // this could be SIGTERM and we should shutdown but how to find out? + rqtp = rmtp; + } +} + +// check for heartbeats and maybe report loss +uint8_t check_heartbeats(uint8_t gc_state) +{ + int hb = jl_atomic_exchange(&heartbeats, 0); + + if (hb <= 0) { + // we didn't get a heartbeat + n_hbs_recvd = 0; + n_hbs_missed++; + + // if we've printed task backtraces already, do nothing + if (!tasks_showed) { + // otherwise, at least show this message + jl_safe_printf("==== heartbeat loss (%ds) ====\n", + n_hbs_missed * heartbeat_interval_s); + // if we've missed enough heartbeats, print task backtraces + if (n_hbs_missed >= tasks_after_n) { + jl_task_t *ct = jl_current_task; + jl_ptls_t ptls = ct->ptls; + + // exit GC-safe region to report then re-enter + jl_gc_safe_leave(ptls, gc_state); + jl_print_task_backtraces(0); + gc_state = jl_gc_safe_enter(ptls); + + // we printed task backtraces + tasks_showed = 1; + } + } + } + else { + // got a heartbeat + n_hbs_recvd++; + // if we'd printed task backtraces, check for reset + if (tasks_showed && n_hbs_recvd >= reset_tasks_after_n) { + tasks_showed = 0; + jl_safe_printf("==== heartbeats recovered (lost for %ds) ====\n", + n_hbs_missed * heartbeat_interval_s); + } + n_hbs_missed = 0; + } + + return gc_state; +} + +// heartbeat thread function +void jl_heartbeat_threadfun(void *arg) +{ + int s = 59, ns = 1e9 - 1, rs; + uint64_t t0, tchb; + + // We need a TLS because backtraces are accumulated into ptls->bt_size + // and ptls->bt_data, so we need to call jl_adopt_thread(). + jl_adopt_thread(); + (void)jl_atomic_fetch_add_relaxed(&n_threads_running, -1); + jl_task_t *ct = jl_current_task; + jl_ptls_t ptls = ct->ptls; + heartbeat_tid = ptls->tid; + + // Don't hold up GC, this thread doesn't participate. + uint8_t gc_state = jl_gc_safe_enter(ptls); + + for (;;) { + if (!heartbeat_enabled) { + // post the off semaphore to indicate we're ready to enable + uv_sem_post(&heartbeat_off_sem); + + // sleep the thread here; this semaphore is posted in + // jl_heartbeat_enable() or jl_heartbeat_resume() + uv_sem_wait(&heartbeat_on_sem); + + // Set the sleep duration. + s = heartbeat_interval_s - 1; + ns = 1e9 - 1; + continue; + } + + // heartbeat is enabled; sleep, waiting for the desired interval + sleep_for(s, ns); + + // if heartbeats were turned off/paused while we were sleeping, reset + if (!heartbeat_enabled) { + continue; + } + + // check if any heartbeats have happened, report as appropriate + t0 = jl_hrtime(); + gc_state = check_heartbeats(gc_state); + tchb = jl_hrtime() - t0; + + // adjust the next sleep duration based on how long the heartbeat + // check took, but if it took too long then use the normal duration + rs = 1; + while (tchb > 1e9) { + rs++; + tchb -= 1e9; + } + if (rs < heartbeat_interval_s) { + s = heartbeat_interval_s - rs; + } + ns = 1e9 - tchb; + } +} + +#else // !JL_HEARTBEAT_THREAD + +void jl_init_heartbeat(void) +{ +} + +int jl_inside_heartbeat_thread(void) +{ + return 0; +} + +JL_DLLEXPORT int jl_heartbeat_enable(int heartbeat_s, int show_tasks_after_n, + int reset_after_n) +{ + return -1; +} + +JL_DLLEXPORT int jl_heartbeat_pause(void) +{ + return -1; +} + +JL_DLLEXPORT int jl_heartbeat_resume(void) +{ + return -1; +} + +JL_DLLEXPORT void jl_heartbeat(void) +{ +} + +#endif // JL_HEARTBEAT_THREAD + #ifdef __cplusplus } #endif From 0cb4f3e0b8d12272bdabbd74aa18e25a2ea9f554 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Fri, 22 Mar 2024 14:06:26 -0300 Subject: [PATCH 77/83] RAI: --safe-crash-log-file flag --- base/options.jl | 1 + src/init.c | 9 ++++++++ src/jl_uv.c | 54 +++++++++++++++++++++++++++++++++++++++++++ src/jloptions.c | 7 ++++++ src/jloptions.h | 1 + src/julia_internal.h | 26 +++++++++++++++++++++ src/signal-handling.c | 2 ++ src/signals-unix.c | 10 +------- src/signals-win.c | 2 +- 9 files changed, 102 insertions(+), 10 deletions(-) diff --git a/base/options.jl b/base/options.jl index 1692c765443f3..b5730994492aa 100644 --- a/base/options.jl +++ b/base/options.jl @@ -64,6 +64,7 @@ struct JLOptions trim::Int8 task_metrics::Int8 timeout_for_safepoint_straggler_s::Int16 + safe_crash_log_file::Ptr{UInt8} end # This runs early in the sysimage != is not defined yet diff --git a/src/init.c b/src/init.c index c0bd6de1e99a4..f9c5409a0fe99 100644 --- a/src/init.c +++ b/src/init.c @@ -759,6 +759,15 @@ JL_DLLEXPORT void jl_init_(jl_image_buf_t sysimage) if (jl_options.handle_signals == JL_OPTIONS_HANDLE_SIGNALS_ON) jl_install_default_signal_handlers(); +#if (defined(_OS_LINUX_) && defined(_CPU_X86_64_)) || (defined(_OS_DARWIN_) && defined(_CPU_AARCH64_)) + if (jl_options.safe_crash_log_file != NULL) { + jl_sig_fd = open(jl_options.safe_crash_log_file, O_WRONLY | O_CREAT | O_APPEND, 0600); + if (jl_sig_fd == -1) { + jl_error("fatal error: could not open safe crash log file for writing"); + } + } +#endif + jl_gc_init(); arraylist_new(&jl_linkage_blobs, 0); diff --git a/src/jl_uv.c b/src/jl_uv.c index a21b05433b8c6..140c022e98a29 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -15,6 +15,7 @@ #include "errno.h" #include #include +#include #endif #include "julia.h" @@ -813,6 +814,56 @@ JL_DLLEXPORT int jl_printf(uv_stream_t *s, const char *format, ...) return c; } +STATIC_INLINE void print_error_msg_as_json(char *buf) JL_NOTSAFEPOINT +{ + // Our telemetry on SPCS expects a JSON object per line + // The following lines prepare the timestamp string and the JSON object + struct timeval tv; + struct tm* tm_info; + char timestamp_buffer[50]; + // Get current time + gettimeofday(&tv, NULL); + tm_info = gmtime(&tv.tv_sec); + // Format time + int offset = strftime(timestamp_buffer, 25, "%Y-%m-%dT%H:%M:%S", tm_info); + // Append milliseconds + snprintf(timestamp_buffer + offset, 25, ".%03d", tv.tv_usec / 1000); + const char *json_preamble_p1 = "\n{\"level\":\"Error\", \"timestamp\":\""; + const char *json_preamble_p2 = "\", \"message\": \""; + const char *json_postamble = "\"}\n"; + // Ignore write failures because there is nothing we can do + write(jl_sig_fd, json_preamble_p1, strlen(json_preamble_p1)); + write(jl_sig_fd, timestamp_buffer, strlen(timestamp_buffer)); + write(jl_sig_fd, json_preamble_p2, strlen(json_preamble_p2)); + // JSON escape the input string + for(size_t i = 0; i < strlen(buf); i += 1) { + switch (buf[i]) { + case '"': + write(jl_sig_fd, "\\\"", 2); + break; + case '\b': + write(jl_sig_fd, "\\b", 2); + break; + case '\n': + write(jl_sig_fd, "\\n", 2); + break; + case '\r': + write(jl_sig_fd, "\\r", 2); + break; + case '\t': + write(jl_sig_fd, "\\t", 2); + break; + case '\\': + write(jl_sig_fd, "\\\\", 2); + break; + default: + write(jl_sig_fd, buf + i, 1); + } + } + write(jl_sig_fd, json_postamble, strlen(json_postamble)); + fdatasync(jl_sig_fd); +} + JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...) { static char buf[1000]; @@ -829,6 +880,9 @@ JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...) va_end(args); buf[999] = '\0'; + if (jl_inside_signal_handler() && jl_sig_fd != 0) { + print_error_msg_as_json(buf); + } if (write(STDERR_FILENO, buf, strlen(buf)) < 0) { // nothing we can do; ignore the failure } diff --git a/src/jloptions.c b/src/jloptions.c index bb4092bb2845d..e128045b5b5af 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -155,6 +155,7 @@ JL_DLLEXPORT void jl_init_options(void) JL_TRIM_NO, // trim 0, // task_metrics -1, // timeout_for_safepoint_straggler_s + NULL, // safe_crash_log_file }; jl_options_initialized = 1; } @@ -384,6 +385,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) opt_permalloc_pkgimg, opt_trim, opt_experimental_features, + opt_safe_crash_log_file, }; static const char* const shortopts = "+vhqH:e:E:L:J:C:it:p:O:g:m:"; static const struct option longopts[] = { @@ -452,6 +454,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) { "permalloc-pkgimg",required_argument, 0, opt_permalloc_pkgimg }, { "heap-size-hint", required_argument, 0, opt_heap_size_hint }, { "trim", optional_argument, 0, opt_trim }, + { "safe-crash-log-file", required_argument, 0, opt_safe_crash_log_file }, { 0, 0, 0, 0 } }; @@ -1013,6 +1016,10 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) jl_options.task_metrics = JL_OPTIONS_TASK_METRICS_ON; else jl_errorf("julia: invalid argument to --task-metrics={yes|no} (%s)", optarg); + case opt_safe_crash_log_file: + jl_options.safe_crash_log_file = strdup(optarg); + if (jl_options.safe_crash_log_file == NULL) + jl_error("julia: failed to allocate memory for --safe-crash-log-file"); break; default: jl_errorf("julia: unhandled option -- %c\n" diff --git a/src/jloptions.h b/src/jloptions.h index 06e00e9309dba..f5c8f72a2cb6c 100644 --- a/src/jloptions.h +++ b/src/jloptions.h @@ -68,6 +68,7 @@ typedef struct { int8_t trim; int8_t task_metrics; int16_t timeout_for_safepoint_straggler_s; + const char *safe_crash_log_file; } jl_options_t; #endif diff --git a/src/julia_internal.h b/src/julia_internal.h index 781997f871841..607236a6df119 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -782,6 +782,32 @@ JL_CALLABLE(jl_f_tuple); void jl_install_default_signal_handlers(void); void restore_signals(void); void jl_install_thread_signal_handler(jl_ptls_t ptls); +extern const size_t sig_stack_size; +STATIC_INLINE int is_addr_on_sigstack(jl_ptls_t ptls, void *ptr) +{ + // One guard page for signal_stack. + return !((char*)ptr < (char*)ptls->signal_stack - jl_page_size || + (char*)ptr > (char*)ptls->signal_stack + sig_stack_size); +} +STATIC_INLINE int jl_inside_signal_handler(void) +{ +#if (defined(_OS_LINUX_) && defined(_CPU_X86_64_)) || (defined(_OS_DARWIN_) && defined(_CPU_AARCH64_)) + // Read the stack pointer + size_t sp; +#if defined(_OS_LINUX_) && defined(_CPU_X86_64_) + __asm__ __volatile__("movq %%rsp, %0" : "=r"(sp)); +#elif defined(_OS_DARWIN_) && defined(_CPU_AARCH64_) + __asm__ __volatile__("mov %0, sp" : "=r"(sp)); +#endif + // Check if the stack pointer is within the signal stack + jl_ptls_t ptls = jl_current_task->ptls; + return is_addr_on_sigstack(ptls, (void*)sp); +#else + return 0; +#endif +} +// File-descriptor for safe logging on signal handling +extern int jl_sig_fd; extern uv_loop_t *jl_io_loop; JL_DLLEXPORT void jl_uv_flush(uv_stream_t *stream); diff --git a/src/signal-handling.c b/src/signal-handling.c index b03f0c1a430cd..6e3f22c87a075 100644 --- a/src/signal-handling.c +++ b/src/signal-handling.c @@ -30,6 +30,8 @@ static const uint64_t GIGA = 1000000000ULL; // Timers to take samples at intervals JL_DLLEXPORT void jl_profile_stop_timer(void); JL_DLLEXPORT int jl_profile_start_timer(uint8_t); +// File-descriptor for safe logging on signal handling +int jl_sig_fd; /////////////////////// // Utility functions // diff --git a/src/signals-unix.c b/src/signals-unix.c index 550f3303aa2b1..ec7610b1ab9a7 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -42,7 +42,7 @@ #endif // 8M signal stack, same as default stack size (though we barely use this) -static const size_t sig_stack_size = 8 * 1024 * 1024; +const size_t sig_stack_size = 8 * 1024 * 1024; #include "julia_assert.h" @@ -102,14 +102,6 @@ static inline uintptr_t jl_get_rsp_from_ctx(const void *_ctx) #endif } -static int is_addr_on_sigstack(jl_ptls_t ptls, void *ptr) JL_NOTSAFEPOINT -{ - // One guard page for signal_stack. - return ptls->signal_stack == NULL || - ((char*)ptr >= (char*)ptls->signal_stack - jl_page_size && - (char*)ptr <= (char*)ptls->signal_stack + (ptls->signal_stack_size ? ptls->signal_stack_size : sig_stack_size)); -} - // Modify signal context `_ctx` so that `fptr` will execute when the signal returns // The function `fptr` itself must not return. JL_NO_ASAN static void jl_call_in_ctx(jl_ptls_t ptls, void (*fptr)(void), int sig, void *_ctx) diff --git a/src/signals-win.c b/src/signals-win.c index c8ae74f52dba4..7f33eeb961624 100644 --- a/src/signals-win.c +++ b/src/signals-win.c @@ -4,7 +4,7 @@ // Note that this file is `#include`d by "signal-handling.c" #include // hidden by LEAN_AND_MEAN -static const size_t sig_stack_size = 131072; // 128k reserved for backtrace_fiber for stack overflow handling +const size_t sig_stack_size = 131072; // 128k reserved for backtrace_fiber for stack overflow handling // Copied from MINGW_FLOAT_H which may not be found due to a collision with the builtin gcc float.h // eventually we can probably integrate this into OpenLibm. From ade7465c8f6bee3634c83ada9c023f366a3f92b2 Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Mon, 27 May 2024 15:39:36 -0400 Subject: [PATCH 78/83] RAI: Write heartbeat thread output to safe crash log --- src/jl_uv.c | 86 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 28 deletions(-) diff --git a/src/jl_uv.c b/src/jl_uv.c index 140c022e98a29..5d8ba54c06c4e 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -814,56 +814,83 @@ JL_DLLEXPORT int jl_printf(uv_stream_t *s, const char *format, ...) return c; } -STATIC_INLINE void print_error_msg_as_json(char *buf) JL_NOTSAFEPOINT +STATIC_INLINE int copystp(char *dest, const char *src) { - // Our telemetry on SPCS expects a JSON object per line - // The following lines prepare the timestamp string and the JSON object + char *d = stpcpy(dest, src); + return (int)(d - dest); +} + +// RAI-specific +STATIC_INLINE void write_to_safe_crash_log(char *buf) JL_NOTSAFEPOINT +{ + int buflen = strlen(buf); + // Our telemetry on SPCS expects a JSON object per line. + // We ignore write failures because there is nothing we can do. + // We'll use a 2K byte buffer: 69 bytes for JSON message decorations, + // 1 byte for the terminating NUL character, and 3 bytes for an + // ellipsis if we have to truncate the message leaves `max_b` bytes + // for the message. + const int wbuflen = 2048; + const int max_b = wbuflen - 70 - 3; + char wbuf[wbuflen]; + bzero(wbuf, wbuflen); + int wlen = 0; + + // JSON preamble (32 bytes) + wlen += copystp(&wbuf[wlen], "\n{\"level\":\"Error\", \"timestamp\":\""); + + // Timestamp (19 bytes) struct timeval tv; struct tm* tm_info; - char timestamp_buffer[50]; - // Get current time gettimeofday(&tv, NULL); tm_info = gmtime(&tv.tv_sec); - // Format time - int offset = strftime(timestamp_buffer, 25, "%Y-%m-%dT%H:%M:%S", tm_info); - // Append milliseconds - snprintf(timestamp_buffer + offset, 25, ".%03d", tv.tv_usec / 1000); - const char *json_preamble_p1 = "\n{\"level\":\"Error\", \"timestamp\":\""; - const char *json_preamble_p2 = "\", \"message\": \""; - const char *json_postamble = "\"}\n"; - // Ignore write failures because there is nothing we can do - write(jl_sig_fd, json_preamble_p1, strlen(json_preamble_p1)); - write(jl_sig_fd, timestamp_buffer, strlen(timestamp_buffer)); - write(jl_sig_fd, json_preamble_p2, strlen(json_preamble_p2)); - // JSON escape the input string - for(size_t i = 0; i < strlen(buf); i += 1) { + wlen += strftime(&wbuf[wlen], 42, "%Y-%m-%dT%H:%M:%S", tm_info); + sprintf(&wbuf[wlen], ".%03ld", (long)tv.tv_usec / 1000); + wlen += 4; + + // JSON preamble to message (15 bytes) + wlen += copystp(&wbuf[wlen], "\", \"message\": \""); + + // Message + // Each iteration will advance wlen by 1 or 2 + for (size_t i = 0; i < buflen; i++) { + // Truncate the message if the write buffer is full + if (wlen == max_b || wlen == max_b - 1) { + wlen += copystp(&wbuf[wlen], "..."); + break; + } switch (buf[i]) { case '"': - write(jl_sig_fd, "\\\"", 2); + wlen += copystp(&wbuf[wlen], "\\\""); break; case '\b': - write(jl_sig_fd, "\\b", 2); + wlen += copystp(&wbuf[wlen], "\\b"); break; case '\n': - write(jl_sig_fd, "\\n", 2); + wlen += copystp(&wbuf[wlen], "\\n"); break; case '\r': - write(jl_sig_fd, "\\r", 2); + wlen += copystp(&wbuf[wlen], "\\r"); break; case '\t': - write(jl_sig_fd, "\\t", 2); + wlen += copystp(&wbuf[wlen], "\\t"); break; case '\\': - write(jl_sig_fd, "\\\\", 2); + wlen += copystp(&wbuf[wlen], "\\\\"); break; default: - write(jl_sig_fd, buf + i, 1); + wbuf[wlen++] = buf[i]; + break; } } - write(jl_sig_fd, json_postamble, strlen(json_postamble)); + // JSON completion (3 bytes) + wlen += copystp(&wbuf[wlen], "\"}\n"); + write(jl_sig_fd, wbuf, wlen); fdatasync(jl_sig_fd); } +extern int jl_inside_heartbeat_thread(void); + JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...) { static char buf[1000]; @@ -880,8 +907,11 @@ JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...) va_end(args); buf[999] = '\0'; - if (jl_inside_signal_handler() && jl_sig_fd != 0) { - print_error_msg_as_json(buf); + // order is important here: we want to ensure that the threading infra + // has been initialized before we start trying to print to the + // safe crash log file + if (jl_sig_fd != 0 && (jl_inside_signal_handler() || jl_inside_heartbeat_thread())) { + write_to_safe_crash_log(buf); } if (write(STDERR_FILENO, buf, strlen(buf)) < 0) { // nothing we can do; ignore the failure From 5ce74906c708a57c78a5168aa654aedc8bca0c85 Mon Sep 17 00:00:00 2001 From: d-netto Date: Mon, 6 Jan 2025 15:17:03 -0300 Subject: [PATCH 79/83] RAI: fix string interpolation on OPENBLAS_BUILD_OPTS --- deps/openblas.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/openblas.mk b/deps/openblas.mk index e5a988ba84df2..80881a6a13c4e 100644 --- a/deps/openblas.mk +++ b/deps/openblas.mk @@ -44,7 +44,7 @@ OPENBLAS_CFLAGS := -O2 # Decide whether to build for 32-bit or 64-bit arch ifneq ($(XC_HOST),) -OPENBLAS_BUILD_OPTS += OSNAME=$(OS) CROSS=1 HOSTCC=$(HOSTCC) CROSS_SUFFIX=$(CROSS_COMPILE) +OPENBLAS_BUILD_OPTS += OSNAME=$(OS) CROSS=1 HOSTCC="$(HOSTCC)" CROSS_SUFFIX=$(CROSS_COMPILE) endif ifeq ($(OS),WINNT) ifneq ($(ARCH),x86_64) From ef079da412ca67f37bcda3930580b41845c18941 Mon Sep 17 00:00:00 2001 From: K Pamnany Date: Mon, 21 Aug 2023 12:10:18 -0400 Subject: [PATCH 80/83] RAI: Prepend signal number and thread ID on backtraces Prepend `[signal (X) ]thread (Y) ` to each backtrace line that is displayed. Co-authored-by: Diogo Netto <61364108+d-netto@users.noreply.github.com> --- src/julia_internal.h | 6 +++--- src/safepoint.c | 2 +- src/signal-handling.c | 2 +- src/signals-unix.c | 2 +- src/signals-win.c | 2 +- src/stackwalk.c | 45 ++++++++++++++++++++++++++++--------------- 6 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/julia_internal.h b/src/julia_internal.h index 607236a6df119..a8172c3e8c1c1 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -1527,9 +1527,9 @@ JL_DLLEXPORT jl_value_t *jl_backtrace_from_here(int returnsp, int skip); void jl_critical_error(int sig, int si_code, bt_context_t *context, jl_task_t *ct); JL_DLLEXPORT void jl_raise_debugger(void) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_gdblookup(void* ip) JL_NOTSAFEPOINT; -void jl_print_native_codeloc(uintptr_t ip) JL_NOTSAFEPOINT; -void jl_print_bt_entry_codeloc(jl_bt_element_t *bt_data) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT; +void jl_print_native_codeloc(char *pre_str, uintptr_t ip) JL_NOTSAFEPOINT; +void jl_print_bt_entry_codeloc(int sig, jl_bt_element_t *bt_data) JL_NOTSAFEPOINT; +JL_DLLEXPORT void jl_print_task_backtraces(int show_done)JL_NOTSAFEPOINT ; #ifdef _OS_WINDOWS_ JL_DLLEXPORT void jl_refresh_dbg_module_list(void); #endif diff --git a/src/safepoint.c b/src/safepoint.c index 970c48875d790..96da3c1a05eb1 100644 --- a/src/safepoint.c +++ b/src/safepoint.c @@ -172,7 +172,7 @@ void jl_gc_wait_for_the_world(jl_ptls_t* gc_all_tls_states, int gc_n_threads) size_t bt_size = jl_try_record_thread_backtrace(ptls2, ptls->bt_data, JL_MAX_BT_SIZE); // Print the backtrace of the straggler for (size_t i = 0; i < bt_size; i += jl_bt_entry_size(ptls->bt_data + i)) { - jl_print_bt_entry_codeloc(ptls->bt_data + i); + jl_print_bt_entry_codeloc(-1, ptls->bt_data + i); } } } diff --git a/src/signal-handling.c b/src/signal-handling.c index 6e3f22c87a075..269885bb5c14c 100644 --- a/src/signal-handling.c +++ b/src/signal-handling.c @@ -649,7 +649,7 @@ void jl_critical_error(int sig, int si_code, bt_context_t *context, jl_task_t *c *bt_size = n = rec_backtrace_ctx(bt_data, JL_MAX_BT_SIZE, context, NULL); } for (i = 0; i < n; i += jl_bt_entry_size(bt_data + i)) { - jl_print_bt_entry_codeloc(bt_data + i); + jl_print_bt_entry_codeloc(sig, bt_data + i); } jl_gc_debug_print_status(); jl_gc_debug_critical_error(); diff --git a/src/signals-unix.c b/src/signals-unix.c index ec7610b1ab9a7..384bad2017126 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -1107,7 +1107,7 @@ static void *signal_listener(void *arg) jl_safe_printf("\nsignal (%d): %s\n", sig, strsignal(sig)); size_t i; for (i = 0; i < signal_bt_size; i += jl_bt_entry_size(signal_bt_data + i)) { - jl_print_bt_entry_codeloc(signal_bt_data + i); + jl_print_bt_entry_codeloc(-1, signal_bt_data + i); } } } diff --git a/src/signals-win.c b/src/signals-win.c index 7f33eeb961624..d9c7ffd5ae769 100644 --- a/src/signals-win.c +++ b/src/signals-win.c @@ -333,7 +333,7 @@ LONG WINAPI jl_exception_handler(struct _EXCEPTION_POINTERS *ExceptionInfo) jl_safe_printf("UNKNOWN"); break; } jl_safe_printf(" at 0x%zx -- ", (size_t)ExceptionInfo->ExceptionRecord->ExceptionAddress); - jl_print_native_codeloc((uintptr_t)ExceptionInfo->ExceptionRecord->ExceptionAddress); + jl_print_native_codeloc("", (uintptr_t)ExceptionInfo->ExceptionRecord->ExceptionAddress); jl_critical_error(0, 0, ExceptionInfo->ContextRecord, ct); static int recursion = 0; diff --git a/src/stackwalk.c b/src/stackwalk.c index 410f4028b6704..ab283b85b59db 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -637,22 +637,25 @@ JL_DLLEXPORT jl_value_t *jl_lookup_code_address(void *ip, int skipC) return rs; } -static void jl_safe_print_codeloc(const char* func_name, const char* file_name, +static void jl_safe_print_codeloc(const char *pre_str, + const char* func_name, const char* file_name, int line, int inlined) JL_NOTSAFEPOINT { const char *inlined_str = inlined ? " [inlined]" : ""; if (line != -1) { - jl_safe_printf("%s at %s:%d%s\n", func_name, file_name, line, inlined_str); + jl_safe_printf("%s%s at %s:%d%s\n", + pre_str, func_name, file_name, line, inlined_str); } else { - jl_safe_printf("%s at %s (unknown line)%s\n", func_name, file_name, inlined_str); + jl_safe_printf("%s%s at %s (unknown line)%s\n", + pre_str, func_name, file_name, inlined_str); } } // Print function, file and line containing native instruction pointer `ip` by // looking up debug info. Prints multiple such frames when `ip` points to // inlined code. -void jl_print_native_codeloc(uintptr_t ip) JL_NOTSAFEPOINT +void jl_print_native_codeloc(char *pre_str, uintptr_t ip) JL_NOTSAFEPOINT { // This function is not allowed to reference any TLS variables since // it can be called from an unmanaged thread on OSX. @@ -664,10 +667,11 @@ void jl_print_native_codeloc(uintptr_t ip) JL_NOTSAFEPOINT for (i = 0; i < n; i++) { jl_frame_t frame = frames[i]; if (!frame.func_name) { - jl_safe_printf("unknown function (ip: %p) at %s\n", (void*)ip, frame.file_name ? frame.file_name : "(unknown file)"); + jl_safe_printf("%sunknown function (ip: %p) at %s\n", pre_str, (void*)ip, frame.file_name ? frame.file_name : "(unknown file)"); } else { - jl_safe_print_codeloc(frame.func_name, frame.file_name, frame.line, frame.inlined); + jl_safe_print_codeloc(pre_str, frame.func_name, + frame.file_name, frame.line, frame.inlined); free(frame.func_name); } free(frame.file_name); @@ -725,7 +729,7 @@ const char *jl_debuginfo_name(jl_value_t *func) // func == module : top-level // func == NULL : macro expansion -static void jl_print_debugloc(jl_debuginfo_t *debuginfo, jl_value_t *func, size_t ip, int inlined) JL_NOTSAFEPOINT +static void jl_print_debugloc(const char *pre_str, jl_debuginfo_t *debuginfo, jl_value_t *func, size_t ip, int inlined) JL_NOTSAFEPOINT { if (!jl_is_symbol(debuginfo->def)) // this is a path or func = debuginfo->def; // this is inlined code @@ -734,26 +738,33 @@ static void jl_print_debugloc(jl_debuginfo_t *debuginfo, jl_value_t *func, size_ if (edges_idx) { jl_debuginfo_t *edge = (jl_debuginfo_t*)jl_svecref(debuginfo->edges, edges_idx - 1); assert(jl_typetagis(edge, jl_debuginfo_type)); - jl_print_debugloc(edge, NULL, stmt.pc, 1); + jl_print_debugloc(pre_str, edge, NULL, stmt.pc, 1); } intptr_t ip2 = stmt.line; if (ip2 >= 0 && ip > 0 && (jl_value_t*)debuginfo->linetable != jl_nothing) { - jl_print_debugloc(debuginfo->linetable, func, ip2, 0); + jl_print_debugloc(pre_str, debuginfo->linetable, func, ip2, 0); } else { if (ip2 < 0) // set broken debug info to ignored ip2 = 0; const char *func_name = jl_debuginfo_name(func); const char *file = jl_debuginfo_file(debuginfo); - jl_safe_print_codeloc(func_name, file, ip2, inlined); + jl_safe_print_codeloc(pre_str, func_name, file, ip2, inlined); } } // Print code location for backtrace buffer entry at *bt_entry -void jl_print_bt_entry_codeloc(jl_bt_element_t *bt_entry) JL_NOTSAFEPOINT +void jl_print_bt_entry_codeloc(int sig, jl_bt_element_t *bt_entry) JL_NOTSAFEPOINT { + char sig_str[32], pre_str[64]; + sig_str[0] = '\0'; + if (sig != -1) { + snprintf(sig_str, 32, "signal (%d) ", sig); + } + snprintf(pre_str, 64, "%sthread (%d) ", sig_str, jl_threadid() + 1); + if (jl_bt_is_native(bt_entry)) { - jl_print_native_codeloc(bt_entry[0].uintptr); + jl_print_native_codeloc(pre_str, bt_entry[0].uintptr); } else if (jl_bt_entry_tag(bt_entry) == JL_BT_INTERP_FRAME_TAG) { size_t ip = jl_bt_entry_header(bt_entry); // zero-indexed @@ -772,7 +783,7 @@ void jl_print_bt_entry_codeloc(jl_bt_element_t *bt_entry) JL_NOTSAFEPOINT if (jl_is_code_info(code)) { jl_code_info_t *src = (jl_code_info_t*)code; // See also the debug info handling in codegen.cpp. - jl_print_debugloc(src->debuginfo, def, ip + 1, 0); + jl_print_debugloc(pre_str, src->debuginfo, def, ip + 1, 0); } else { // If we're using this function something bad has already happened; @@ -1361,7 +1372,9 @@ JL_DLLEXPORT jl_record_backtrace_result_t jl_record_backtrace(jl_task_t *t, jl_b JL_DLLEXPORT void jl_gdblookup(void* ip) { - jl_print_native_codeloc((uintptr_t)ip); + char pre_str[64]; + snprintf(pre_str, 64, "thread (%d) ", jl_threadid() + 1); + jl_print_native_codeloc(pre_str, (uintptr_t)ip); } // Print backtrace for current exception in catch block @@ -1376,7 +1389,7 @@ JL_DLLEXPORT void jlbacktrace(void) JL_NOTSAFEPOINT size_t i, bt_size = jl_excstack_bt_size(s, s->top); jl_bt_element_t *bt_data = jl_excstack_bt_data(s, s->top); for (i = 0; i < bt_size; i += jl_bt_entry_size(bt_data + i)) { - jl_print_bt_entry_codeloc(bt_data + i); + jl_print_bt_entry_codeloc(-1, bt_data + i); } } @@ -1399,7 +1412,7 @@ JL_DLLEXPORT void jlbacktracet(jl_task_t *t) JL_NOTSAFEPOINT size_t bt_size = r.bt_size; size_t i; for (i = 0; i < bt_size; i += jl_bt_entry_size(bt_data + i)) { - jl_print_bt_entry_codeloc(bt_data + i); + jl_print_bt_entry_codeloc(-1, bt_data + i); } if (bt_size == 0) jl_safe_printf(" no backtrace recorded\n"); From e8145dabbefc3e16ed76b68dff6508f2b7afebc9 Mon Sep 17 00:00:00 2001 From: K Pamnany Date: Thu, 18 Apr 2024 16:36:27 -0400 Subject: [PATCH 81/83] RAI: do not prepend thread ID to backtraces from signal handler context Also show the signal number when we have it. --- src/signals-unix.c | 2 +- src/stackwalk.c | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/signals-unix.c b/src/signals-unix.c index 384bad2017126..ed186d5b357cd 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -1107,7 +1107,7 @@ static void *signal_listener(void *arg) jl_safe_printf("\nsignal (%d): %s\n", sig, strsignal(sig)); size_t i; for (i = 0; i < signal_bt_size; i += jl_bt_entry_size(signal_bt_data + i)) { - jl_print_bt_entry_codeloc(-1, signal_bt_data + i); + jl_print_bt_entry_codeloc(sig, signal_bt_data + i); } } } diff --git a/src/stackwalk.c b/src/stackwalk.c index ab283b85b59db..b04142f7cf845 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -757,11 +757,14 @@ static void jl_print_debugloc(const char *pre_str, jl_debuginfo_t *debuginfo, jl void jl_print_bt_entry_codeloc(int sig, jl_bt_element_t *bt_entry) JL_NOTSAFEPOINT { char sig_str[32], pre_str[64]; - sig_str[0] = '\0'; + sig_str[0] = pre_str[0] = '\0'; if (sig != -1) { snprintf(sig_str, 32, "signal (%d) ", sig); } - snprintf(pre_str, 64, "%sthread (%d) ", sig_str, jl_threadid() + 1); + // do not call jl_threadid if there's no current task + if (jl_get_current_task()) { + snprintf(pre_str, 64, "%sthread (%d) ", sig_str, jl_threadid() + 1); + } if (jl_bt_is_native(bt_entry)) { jl_print_native_codeloc(pre_str, bt_entry[0].uintptr); @@ -1373,7 +1376,11 @@ JL_DLLEXPORT jl_record_backtrace_result_t jl_record_backtrace(jl_task_t *t, jl_b JL_DLLEXPORT void jl_gdblookup(void* ip) { char pre_str[64]; - snprintf(pre_str, 64, "thread (%d) ", jl_threadid() + 1); + pre_str[0] = '\0'; + // do not call jl_threadid if there's no current task + if (jl_get_current_task()) { + snprintf(pre_str, 64, "thread (%d) ", jl_threadid() + 1); + } jl_print_native_codeloc(pre_str, (uintptr_t)ip); } @@ -1441,7 +1448,11 @@ JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT size_t nthreads = jl_atomic_load_acquire(&jl_n_threads); jl_ptls_t *allstates = jl_atomic_load_relaxed(&jl_all_tls_states); - int ctid = jl_threadid() + 1; + int ctid = -1; + // do not call jl_threadid if there's no current task + if (jl_get_current_task()) { + ctid = jl_threadid() + 1; + } jl_safe_printf("thread (%d) ++++ Task backtraces\n", ctid); for (size_t i = 0; i < nthreads; i++) { jl_ptls_t ptls2 = allstates[i]; From 9e34cdab96b914fa589da8226701a07f9ce2049d Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Wed, 2 Jul 2025 12:28:26 -0400 Subject: [PATCH 82/83] Add `Base.isprecompilable` (#58805) Alternative to https://github.com/JuliaLang/julia/pull/58146. We want to compile a subset of the possible specializations of a function. To this end, we have a number of manually written `precompile` statements. Creating this list is, unfortunately, error-prone, and the list is also liable to going stale. Thus we'd like to validate each `precompile` statement in the list. The simple answer is, of course, to actually run the `precompile`s, and we naturally do so, but this takes time. We would like a relatively quick way to check the validity of a `precompile` statement. This is a dev-loop optimization, to allow us to check "is-precompilable" in unit tests. We can't use `hasmethod` as it has both false positives (too loose): ```julia julia> hasmethod(sum, (AbstractVector,)) true julia> precompile(sum, (AbstractVector,)) false julia> Base.isprecompilable(sum, (AbstractVector,)) # <- this PR false ``` and also false negatives (too strict): ```julia julia> bar(@nospecialize(x::AbstractVector{Int})) = 42 bar (generic function with 1 method) julia> hasmethod(bar, (AbstractVector,)) false julia> precompile(bar, (AbstractVector,)) true julia> Base.isprecompilable(bar, (AbstractVector,)) # <- this PR true ``` We can't use `hasmethod && isconcretetype` as it has false negatives (too strict): ```julia julia> has_concrete_method(f, argtypes) = all(isconcretetype, argtypes) && hasmethod(f, argtypes) has_concrete_method (generic function with 1 method) julia> has_concrete_method(bar, (AbstractVector,)) false julia> has_concrete_method(convert, (Type{Int}, Int32)) false julia> precompile(convert, (Type{Int}, Int32)) true julia> Base.isprecompilable(convert, (Type{Int}, Int32)) # <- this PR true ``` `Base.isprecompilable` is essentially `precompile` without the actual compilation. --- base/loading.jl | 14 ++++++++++++++ src/gf.c | 9 +++++++++ src/jl_exported_funcs.inc | 1 + 3 files changed, 24 insertions(+) diff --git a/base/loading.jl b/base/loading.jl index 40db7df679b60..a804cc5f54706 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -4211,6 +4211,20 @@ function expand_compiler_path(tup) end compiler_chi(tup::Tuple) = CacheHeaderIncludes(expand_compiler_path(tup)) +""" + isprecompilable(f, argtypes::Tuple{Vararg{Any}}) + +Check, as far as is possible without actually compiling, if the given +function `f` can be compiled for the argument tuple (of types) `argtypes`. +""" +function isprecompilable(@nospecialize(f), @nospecialize(argtypes::Tuple)) + isprecompilable(Tuple{Core.Typeof(f), argtypes...}) +end + +function isprecompilable(@nospecialize(argt::Type)) + ccall(:jl_is_compilable, Int32, (Any,), argt) != 0 +end + """ precompile(f, argtypes::Tuple{Vararg{Any}}) diff --git a/src/gf.c b/src/gf.c index 2c5abf7343d09..53415ba4716fd 100644 --- a/src/gf.c +++ b/src/gf.c @@ -3894,6 +3894,15 @@ JL_DLLEXPORT void jl_compile_method_sig(jl_method_t *m, jl_value_t *types, jl_sv jl_compile_method_instance(mi, NULL, world); } +JL_DLLEXPORT int jl_is_compilable(jl_tupletype_t *types) +{ + size_t world = jl_atomic_load_acquire(&jl_world_counter); + size_t min_valid = 0; + size_t max_valid = ~(size_t)0; + jl_method_instance_t *mi = jl_get_compile_hint_specialization(types, world, &min_valid, &max_valid, 1); + return mi == NULL ? 0 : 1; +} + JL_DLLEXPORT int jl_compile_hint(jl_tupletype_t *types) { size_t world = jl_atomic_load_acquire(&jl_world_counter); diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index 4f2b5b7cfdd8f..aee7f0974359f 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -271,6 +271,7 @@ XX(jl_istopmod) \ XX(jl_is_binding_deprecated) \ XX(jl_is_char_signed) \ + XX(jl_is_compilable) \ XX(jl_is_const) \ XX(jl_is_assertsbuild) \ XX(jl_is_debugbuild) \ From 69c4135cf6e64c0a2e77f7eb4596e9b2dad8998a Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Fri, 16 Jan 2026 09:11:48 -0700 Subject: [PATCH 83/83] Fix GC corruption via two upstream PRs. (#272) * Preserve the scope across the exception handler (#60647) We store the previous scope in the eh_state and thus hide it from GC. This means we need to manually preserve that scope across the `try ... catch`, instead fo the new scope that we switch to. --------- Co-authored-by: Nathan Daly Co-authored-by: Keno Fischer * add wb_back on all task switch paths (#60617) Since this task's stack or scope field could have been modified after it was marked by an incremental collection (and not just for copy stacks), move the barrier back unconditionally here. --------- Co-authored-by: Valentin Churavy Co-authored-by: Jeff Bezanson --------- Co-authored-by: Valentin Churavy Co-authored-by: Keno Fischer Co-authored-by: Jameson Nash Co-authored-by: Jeff Bezanson --- src/gc-interface.h | 2 +- test/scopedvalues.jl | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/gc-interface.h b/src/gc-interface.h index c67b7720e70a5..9c59e274d1261 100644 --- a/src/gc-interface.h +++ b/src/gc-interface.h @@ -240,7 +240,7 @@ STATIC_INLINE void jl_gc_wb(const void *parent, const void *ptr) JL_NOTSAFEPOINT // so write barriers can be omitted until the next allocation. This function is a no-op that // can be used to annotate that a write barrier would be required were it not for this property // (as opposed to somebody just having forgotten to think about write barriers). -STATIC_INLINE void jl_gc_wb_fresh(const void *parent, const void *ptr) JL_NOTSAFEPOINT {} +STATIC_INLINE void jl_gc_wb_fresh(const void *parent JL_UNUSED, const void *ptr JL_UNUSED) JL_NOTSAFEPOINT {} // As an optimization, the current_task is explicitly added to the remset while it is running. // Upon deschedule, we conservatively move the write barrier into the young generation. // This allows the omission of write barriers for all GC roots on the current task stack (JL_GC_PUSH_*), diff --git a/test/scopedvalues.jl b/test/scopedvalues.jl index 20f709f755915..500b9647f8da6 100644 --- a/test/scopedvalues.jl +++ b/test/scopedvalues.jl @@ -196,6 +196,34 @@ nothrow_scope() end end +# LazyScopedValue +global lsv_ncalled = 0 +const lsv = LazyScopedValue{Int}(OncePerProcess(() -> (global lsv_ncalled; lsv_ncalled += 1; 1))) +@testset "LazyScopedValue" begin + @test (@with lsv=>2 lsv[]) == 2 + @test lsv_ncalled == 0 + @test lsv[] == 1 + @test lsv_ncalled == 1 + @test lsv[] == 1 + @test lsv_ncalled == 1 +end + +@testset "ScopedThunk" begin + function check_svals() + @test sval[] == 8 + @test sval_float[] == 8.0 + end + sf = nothing + @with sval=>8 sval_float=>8.0 begin + sf = ScopedThunk(check_svals) + end + sf() + @with sval=>8 sval_float=>8.0 begin + sf2 = ScopedThunk{Function}(check_svals) + end + sf2() +end + using Base.ScopedValues: ScopedValue, with @noinline function test_59483() sv = ScopedValue([])